Add to add/remove rule list
[platform/core/connectivity/stc-iptables.git] / src / helper / helper-ip6tables.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License version 2 as
6  *  published by the Free Software Foundation.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <glib.h>
22 #include <arpa/inet.h>
23 #include <xtables.h>
24
25 #include <linux/netfilter.h>
26 #include <linux/netfilter/xt_cgroup.h>
27 #include <linux/netfilter/xt_nfacct.h>
28 #include <linux/netfilter/xt_iprange.h>
29 #include <linux/netfilter/xt_NFLOG.h>
30 #include <linux/netfilter_ipv6/ip6t_LOG.h>
31
32 #include "stc-iptables-error.h"
33 #include "helper-ip6tables.h"
34 #include "helper-log.h"
35
36 #define IP6T_ALIGN    XT_ALIGN
37 #define IP6TC_TABLE   "filter"
38 #define IP6TC_TCP     "tcp"
39 #define IP6TC_UDP     "udp"
40 #define IP6TC_CGROUP  "cgroup"
41 #define IP6TC_NFACCT  "nfacct"
42 #define IP6TC_IPRANGE "iprange"
43 #define IP6TC_LOG     "LOG"
44 #define IP6TC_NFLOG   "NFLOG"
45
46 #define IP6TC_MASK   "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF"
47
48 #define IP6TC_INSERT_RULENUM 0
49
50 /* handle */
51 typedef struct xtc_handle            ip6t_handle_t;
52
53 /* entry */
54 typedef struct ip6t_entry            ip6t_entry_t;
55 typedef struct ip6t_entry_match      ip6t_entry_match_t;
56 typedef struct ip6t_entry_target     ip6t_entry_target_t;
57
58 /* matches */
59 typedef struct xt_tcp                ip6t_tcp_info_t;
60 typedef struct xt_udp                ip6t_udp_info_t;
61 typedef struct xt_cgroup_info_v0     ip6t_cgroup_info_t;
62 typedef struct xt_nfacct_match_info  ip6t_nfacct_info_t;
63 typedef struct xt_iprange_mtinfo     ip6t_iprange_info_t;
64
65 /* target */
66 typedef struct ip6t_log_info         ip6t_log_info_t;
67 typedef struct xt_nflog_info         ip6t_nflog_info_t;
68
69 #define SIZE_ENTRY IP6T_ALIGN(sizeof(ip6t_entry_t))
70 #define SIZE_TCP_MATCH IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(sizeof(ip6t_tcp_info_t))
71 #define SIZE_UDP_MATCH IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(sizeof(ip6t_udp_info_t))
72 #define SIZE_CGROUP_MATCH IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(sizeof(ip6t_cgroup_info_t))
73 #define SIZE_NFACCT_MATCH IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(sizeof(ip6t_nfacct_info_t))
74 #define SIZE_IPRANGE_MATCH IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(sizeof(ip6t_iprange_info_t))
75 #define SIZE_TARGET IP6T_ALIGN(sizeof(ip6t_entry_target_t)) + IP6T_ALIGN(sizeof(int))
76 #define SIZE_TARGET_LOG IP6T_ALIGN(sizeof(ip6t_log_info_t))
77 #define SIZE_TARGET_NFLOG IP6T_ALIGN(sizeof(ip6t_nflog_info_t))
78 #define SIZE_TOTAL SIZE_ENTRY + SIZE_TCP_MATCH + SIZE_UDP_MATCH + SIZE_CGROUP_MATCH \
79                                         + SIZE_NFACCT_MATCH + SIZE_IPRANGE_MATCH + SIZE_TARGET \
80                                         + SIZE_TARGET_LOG + SIZE_TARGET_NFLOG
81
82 static unsigned int __add_match(const char *name, ip6t_entry_match_t *start,
83                                                                                 int revision, size_t size, void *data)
84 {
85         ip6t_entry_match_t *match = start;
86
87         match->u.match_size = IP6T_ALIGN(sizeof(ip6t_entry_match_t)) + IP6T_ALIGN(size);
88
89         g_strlcpy(match->u.user.name, name, XT_EXTENSION_MAXNAMELEN);
90         memcpy(match->data, data, size);
91         match->u.user.revision = revision;
92
93         return match->u.match_size;
94 }
95
96 static unsigned int __add_target(const char *name, ip6t_entry_target_t *start, size_t size, void *data)
97 {
98         ip6t_entry_target_t *target = start;
99
100         target->u.target_size = IP6T_ALIGN(sizeof(ip6t_entry_target_t)) + IP6T_ALIGN(size);
101
102         g_strlcpy(target->u.user.name, name, XT_EXTENSION_MAXNAMELEN);
103         memcpy(target->data, data, size);
104
105         return target->u.target_size;
106 }
107
108 static unsigned int __add_iprange_match(ip6tables_ip_type_e sip_type,
109                 struct in6_addr sip1, struct in6_addr sip2, ip6tables_ip_type_e dip_type,
110                 struct in6_addr dip1, struct in6_addr dip2, ip6t_entry_match_t *start)
111 {
112         ip6t_iprange_info_t iprange;
113         memset(&iprange, 0, sizeof(ip6t_iprange_info_t));
114
115         /* iprange => "--src-range " */
116         if (sip_type == IP6TABLES_IP_RANGE) {
117                 memcpy(&(iprange.src_min.in6), &sip1, sizeof(struct in6_addr));
118                 memcpy(&(iprange.src_max.in6), &sip2, sizeof(struct in6_addr));
119                 iprange.flags |= IPRANGE_SRC;
120         }
121
122         /* iprange => "--dst-range " */
123         if (dip_type == IP6TABLES_IP_RANGE) {
124                 memcpy(&(iprange.dst_min.in6), &dip1, sizeof(struct in6_addr));
125                 memcpy(&(iprange.dst_max.in6), &dip2, sizeof(struct in6_addr));
126                 iprange.flags |= IPRANGE_DST;
127         }
128
129         /* match_iprange => "-m iprange" */
130         return __add_match(IP6TC_IPRANGE, start, 1, sizeof(ip6t_iprange_info_t), &iprange);
131 }
132
133 static void __add_iprange(unsigned char *entry, unsigned int *size_mask,
134                 unsigned int *size_match, ip6tables_rule_s *rule)
135 {
136         ip6t_entry_t *e = (ip6t_entry_t *)(entry);
137
138         (*size_match) += __add_iprange_match(rule->s_ip_type,
139                 rule->s_ip1, rule->s_ip2, rule->d_ip_type, rule->d_ip1,
140                 rule->d_ip2, (ip6t_entry_match_t *)(e->elems + (*size_match)));
141
142         (*size_mask) += sizeof(ip6t_entry_match_t);
143         e->target_offset += SIZE_IPRANGE_MATCH;
144         e->next_offset += SIZE_IPRANGE_MATCH;
145 }
146
147 static unsigned int __add_port_match(ip6tables_protocol_type_e prot_type,
148                 ip6tables_port_type_e sport_type, unsigned short sport1, unsigned short sport2,
149                 ip6tables_port_type_e dport_type, unsigned short dport1, unsigned short dport2,
150                 ip6t_entry_match_t *start)
151 {
152         switch (prot_type) {
153         case IP6TABLES_PROTOCOL_TCP:
154                 {
155                         ip6t_tcp_info_t tcp;
156                         memset(&tcp, 0, sizeof(ip6t_tcp_info_t));
157                         switch(sport_type) {
158                         /* --sport 80 */
159                         case IP6TABLES_PORT_SINGLE:
160                                 tcp.spts[0] = ntohs(htons(sport1));
161                                 tcp.spts[1] = ntohs(htons(sport1));
162                                 break;
163                         /* --sport 0:59136 */
164                         case IP6TABLES_PORT_RANGE:
165                                 tcp.spts[0] = ntohs(htons(sport1));
166                                 tcp.spts[1] = ntohs(htons(sport2));
167                                 break;
168                         default:
169                                 break;
170                         }
171                         switch(dport_type) {
172                         /* --dport 80 */
173                         case IP6TABLES_PORT_SINGLE:
174                                 tcp.dpts[0] = ntohs(htons(dport1));
175                                 tcp.dpts[1] = ntohs(htons(dport1));
176                                 break;
177                         /* --dport 0:59136 */
178                         case IP6TABLES_PORT_RANGE:
179                                 tcp.dpts[0] = ntohs(htons(dport1));
180                                 tcp.dpts[1] = ntohs(htons(dport2));
181                                 break;
182                         default:
183                                 break;
184                         }
185                         return __add_match(IP6TC_TCP, start, 0, sizeof(ip6t_tcp_info_t), &tcp);
186                 }
187         case IP6TABLES_PROTOCOL_UDP:
188                 {
189                         ip6t_udp_info_t udp;
190                         memset(&udp, 0, sizeof(ip6t_udp_info_t));
191                         switch(sport_type) {
192                         /* --sport 80 */
193                         case IP6TABLES_PORT_SINGLE:
194                                 udp.spts[0] = ntohs(htons(sport1));
195                                 udp.spts[1] = ntohs(htons(sport1));
196                                 break;
197                         /* --sport 0:59136 */
198                         case IP6TABLES_PORT_RANGE:
199                                 udp.spts[0] = ntohs(htons(sport1));
200                                 udp.spts[1] = ntohs(htons(sport2));
201                                 break;
202                         default:
203                                 break;
204                         }
205                         switch(dport_type) {
206                         /* --dport 80 */
207                         case IP6TABLES_PORT_SINGLE:
208                                 udp.dpts[0] = ntohs(htons(dport1));
209                                 udp.dpts[1] = ntohs(htons(dport1));
210                                 break;
211                         /* --dport 0:59136 */
212                         case IP6TABLES_PORT_RANGE:
213                                 udp.dpts[0] = ntohs(htons(dport1));
214                                 udp.dpts[1] = ntohs(htons(dport2));
215                                 break;
216                         default:
217                                 break;
218                         }
219                         return __add_match(IP6TC_UDP, start, 0, sizeof(ip6t_udp_info_t), &udp);
220                 }
221         default:
222                 break;
223         }
224
225         return 0;
226 }
227
228 static void __add_port(unsigned char *entry, unsigned int *size_mask,
229                 unsigned int *size_match, ip6tables_rule_s *rule, unsigned int match_size)
230 {
231         if ((rule->s_port_type > IP6TABLES_PORT_NONE &&
232                 rule->s_port_type <= IP6TABLES_PORT_RANGE) ||
233                 (rule->d_port_type > IP6TABLES_PORT_NONE &&
234                 rule->d_port_type <= IP6TABLES_PORT_RANGE)) {
235
236                 ip6t_entry_t *e = (ip6t_entry_t *)(entry);
237
238                 (*size_match) += __add_port_match(rule->protocol,
239                         rule->s_port_type, rule->s_port1, rule->s_port2,
240                         rule->d_port_type, rule->d_port1, rule->d_port2,
241                         (ip6t_entry_match_t *) (e->elems + (*size_match)));
242
243                 (*size_mask) += sizeof(ip6t_entry_match_t);
244                 e->target_offset += match_size;
245                 e->next_offset += match_size;
246         }
247 }
248
249 static unsigned int __add_cgroup_match(unsigned int classid, ip6t_entry_match_t *start)
250 {
251         /* cgroup => "--cgroup 0" */
252         ip6t_cgroup_info_t cgroup;
253         memset(&cgroup, 0, sizeof(ip6t_cgroup_info_t));
254         cgroup.id = classid;
255         /* match_cgroup => "-m cgroup" */
256         return __add_match(IP6TC_CGROUP, start, 0, sizeof(ip6t_cgroup_info_t), &cgroup);
257 }
258
259 static unsigned int __add_nfacct_match(const char *nfacct_name, ip6t_entry_match_t *start)
260 {
261         /* nfacct => "--nfacct_name " */
262         ip6t_nfacct_info_t nfacct;
263         memset(&nfacct, 0, sizeof(ip6t_nfacct_info_t));
264         g_strlcpy(nfacct.name, nfacct_name, NFACCT_NAME_MAX);
265         /* match_nfacct => "-m nfacct" */
266         return __add_match(IP6TC_NFACCT, start, 0, sizeof(ip6t_nfacct_info_t), &nfacct);
267 }
268
269 static unsigned int __add_log_target(unsigned char level, const char *prefix,
270                                                 ip6t_entry_target_t *start)
271 {
272         /* log => "--log-level --log-prefix" */
273         ip6t_log_info_t log;
274         memset(&log, 0, sizeof(ip6t_log_info_t));
275         log.level = level;
276         g_strlcpy(log.prefix, prefix, 30);
277         /* target_log */
278         return __add_target(IP6TC_LOG, start, sizeof(ip6t_log_info_t), &log);
279 }
280
281 static unsigned int __add_nflog_target(unsigned int group, const char *prefix,
282                                                 unsigned int range, unsigned int threshold, ip6t_entry_target_t *start)
283 {
284         /* nflog => "--nflog-group --nflog-prefix --nflog-range --nflog-threshold" */
285         ip6t_nflog_info_t nflog;
286         memset(&nflog, 0, sizeof(ip6t_nflog_info_t));
287         nflog.group = group;
288         g_strlcpy(nflog.prefix, prefix, 64);
289         nflog.len = range;
290         nflog.threshold = threshold;
291         /* target_nflog */
292         return __add_target(IP6TC_NFLOG, start, sizeof(ip6t_nflog_info_t), &nflog);
293 }
294
295 static int __create_entry_data(unsigned char *entry, unsigned char *mask,
296                                ip6tables_rule_s *rule)
297 {
298         ip6t_entry_t *e = NULL;
299         ip6t_entry_target_t *target = NULL;
300         unsigned int size_mask = 0;
301         unsigned int size_match = 0;
302
303         if (!rule->chain) {
304                 STC_LOGE("Invalid parameters"); //LCOV_EXCL_LINE
305                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
306         }
307
308         e = (ip6t_entry_t *)(entry);
309
310         /* entry size */
311         e->target_offset = SIZE_ENTRY;
312         e->next_offset = SIZE_ENTRY;
313         size_mask = sizeof(ip6t_entry_t);
314
315         if (rule->ifname && rule->ifname[0] != '\0') {
316                 switch (rule->direction) {
317                 case IP6TABLES_DIRECTION_IN:
318                         /* entry => "-i wlan0" */
319                         g_strlcpy(e->ipv6.iniface, rule->ifname, IFNAMSIZ);
320                         memset(&(e->ipv6.iniface_mask), 0xFF, IFNAMSIZ);
321                         break;
322                 case IP6TABLES_DIRECTION_OUT:
323                         /* entry => "-o wlan0" */
324                         g_strlcpy(e->ipv6.outiface, rule->ifname, IFNAMSIZ);
325                         memset(&(e->ipv6.outiface_mask), 0xFF, IFNAMSIZ);
326                         break;
327                 default:
328                         STC_LOGE("Invalid parameter"); //LCOV_EXCL_LINE
329                         return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
330                 }
331         }
332
333         switch (rule->s_ip_type) {
334         case IP6TABLES_IP_SINGLE:
335                 /* -s 2001:DB8::5/128 */
336                 e->ipv6.src.s6_addr32[0] = rule->s_ip1.s6_addr32[0];
337                 e->ipv6.src.s6_addr32[1] = rule->s_ip1.s6_addr32[1];
338                 e->ipv6.src.s6_addr32[2] = rule->s_ip1.s6_addr32[2];
339                 e->ipv6.src.s6_addr32[3] = rule->s_ip1.s6_addr32[3];
340                 inet_pton(AF_INET6, IP6TC_MASK, &(e->ipv6.smsk));
341                 break;
342         case IP6TABLES_IP_MASK:
343                 /* -s 2001:DB8::5/64 */
344                 e->ipv6.src.s6_addr32[0] = rule->s_ip1.s6_addr32[0];
345                 e->ipv6.src.s6_addr32[1] = rule->s_ip1.s6_addr32[1];
346                 e->ipv6.src.s6_addr32[2] = rule->s_ip1.s6_addr32[2];
347                 e->ipv6.src.s6_addr32[3] = rule->s_ip1.s6_addr32[3];
348                 e->ipv6.smsk.s6_addr32[0] = rule->s_ip2.s6_addr32[0];
349                 e->ipv6.smsk.s6_addr32[1] = rule->s_ip2.s6_addr32[1];
350                 e->ipv6.smsk.s6_addr32[2] = rule->s_ip2.s6_addr32[2];
351                 e->ipv6.smsk.s6_addr32[3] = rule->s_ip2.s6_addr32[3];
352                 break;
353         default:
354                 break;
355         }
356
357         switch (rule->d_ip_type) {
358         case IP6TABLES_IP_SINGLE:
359                 /* -d 2001:DB8::5/128 */
360                 e->ipv6.dst.s6_addr32[0] = rule->d_ip1.s6_addr32[0];
361                 e->ipv6.dst.s6_addr32[1] = rule->d_ip1.s6_addr32[1];
362                 e->ipv6.dst.s6_addr32[2] = rule->d_ip1.s6_addr32[2];
363                 e->ipv6.dst.s6_addr32[3] = rule->d_ip1.s6_addr32[3];
364                 inet_pton(AF_INET6, IP6TC_MASK, &(e->ipv6.dmsk));
365                 break;
366         case IP6TABLES_IP_MASK:
367                 /* -d 2001:DB8::5/128 */
368                 e->ipv6.dst.s6_addr32[0] = rule->d_ip1.s6_addr32[0];
369                 e->ipv6.dst.s6_addr32[1] = rule->d_ip1.s6_addr32[1];
370                 e->ipv6.dst.s6_addr32[2] = rule->d_ip1.s6_addr32[2];
371                 e->ipv6.dst.s6_addr32[3] = rule->d_ip1.s6_addr32[3];
372                 e->ipv6.dmsk.s6_addr32[0] = rule->d_ip2.s6_addr32[0];
373                 e->ipv6.dmsk.s6_addr32[1] = rule->d_ip2.s6_addr32[1];
374                 e->ipv6.dmsk.s6_addr32[2] = rule->d_ip2.s6_addr32[2];
375                 e->ipv6.dmsk.s6_addr32[3] = rule->d_ip2.s6_addr32[3];
376                 break;
377         default:
378                 break;
379         }
380
381         if (rule->s_ip_type == IP6TABLES_IP_RANGE ||
382                 rule->d_ip_type == IP6TABLES_IP_RANGE)
383                 __add_iprange(entry, &size_mask, &size_match, rule);
384
385         /* -p tcp */
386         switch (rule->protocol) {
387         case IP6TABLES_PROTOCOL_TCP:
388                 e->ipv6.proto = IPPROTO_TCP;
389                 __add_port(entry, &size_mask, &size_match, rule, SIZE_TCP_MATCH);
390                 break;
391         case IP6TABLES_PROTOCOL_UDP:
392                 e->ipv6.proto = IPPROTO_UDP;
393                 __add_port(entry, &size_mask, &size_match, rule, SIZE_UDP_MATCH);
394                 break;
395         case IP6TABLES_PROTOCOL_ICMP:
396                 e->ipv6.proto = IPPROTO_ICMP;
397                 break;
398         case IP6TABLES_PROTOCOL_ESP:
399                 e->ipv6.proto = IPPROTO_ESP;
400                 break;
401         case IP6TABLES_PROTOCOL_AH:
402                 e->ipv6.proto = IPPROTO_AH;
403                 break;
404         case IP6TABLES_PROTOCOL_SCTP:
405                 e->ipv6.proto = IPPROTO_SCTP;
406                 break;
407         case IP6TABLES_PROTOCOL_MH:
408                 e->ipv6.proto = IPPROTO_MH;
409                 break;
410         case IP6TABLES_PROTOCOL_ALL:
411                 e->ipv6.proto = 0;
412                 break;
413         default:
414                 e->ipv6.proto = 0;
415                 break;
416         }
417
418         /* -m cgroup --cgroup 33 */
419         if (rule->classid > 0) {
420                 size_match += __add_cgroup_match(rule->classid, (ip6t_entry_match_t *) e->elems);
421                 size_mask += sizeof(ip6t_entry_match_t);
422                 e->target_offset += SIZE_CGROUP_MATCH;
423                 e->next_offset += SIZE_CGROUP_MATCH;
424         }
425
426         /* -m nfacct --nfacct-name  c2_1_33_seth_w0 */
427         if (rule->nfacct_name && rule->nfacct_name[0] != '\0') {
428                 size_match += __add_nfacct_match(rule->nfacct_name, (ip6t_entry_match_t *) (e->elems + size_match));
429                 size_mask += sizeof(ip6t_entry_match_t);
430                 e->target_offset += SIZE_NFACCT_MATCH;
431                 e->next_offset += SIZE_NFACCT_MATCH;
432         }
433
434         /* target => "-j ACCEPT" */
435         target = (ip6t_entry_target_t *) (e->elems + size_match);
436         switch (rule->target_type) {
437         case IP6TABLES_ACTION_LOG:
438                 e->next_offset += __add_log_target(rule->log_level, rule->log_prefix, target);
439                 break;
440         case IP6TABLES_ACTION_NFLOG:
441                 e->next_offset += __add_nflog_target(rule->nflog_group,
442                         rule->nflog_prefix, rule->nflog_range, rule->nflog_threshold, target);
443                 break;
444         default:
445                 target->u.target_size = SIZE_TARGET;
446                 if (rule->target && rule->target[0] != '\0')
447                         g_strlcpy(target->u.user.name, rule->target, XT_EXTENSION_MAXNAMELEN);
448                 e->next_offset += SIZE_TARGET;
449                 break;
450         }
451
452         memset(mask, 0xFF, size_mask);
453
454         return STC_ERROR_NONE;
455 }
456
457 int ip6tables_add_rule(ip6tables_rule_s *rule)
458 {
459         ip6t_handle_t *handle;
460         unsigned char entry[SIZE_TOTAL] = {0, };
461         unsigned char mask[SIZE_TOTAL] = {0, };
462
463         const char *chain = rule->chain;
464
465         if (__create_entry_data(entry, mask, rule) != 0) {
466                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
467                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
468         }
469
470         handle = ip6tc_init(IP6TC_TABLE);
471         if (handle == NULL) {
472                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
473                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
474         }
475
476         if (!ip6tc_is_chain(chain, handle)) {
477                 STC_LOGW("chain not present [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
478                 ip6tc_free(handle); //LCOV_EXCL_LINE
479                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
480         }
481
482         if (ip6tc_check_entry(chain, (const ip6t_entry_t *)entry, mask, handle)) {
483                 STC_LOGW("Entry already present"); //LCOV_EXCL_LINE
484                 ip6tc_free(handle); //LCOV_EXCL_LINE
485                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
486         }
487
488         if (!ip6tc_append_entry(chain, (const ip6t_entry_t *)entry, handle)) {
489                 STC_LOGW("ip6tc_append_entry failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
490                 ip6tc_free(handle); //LCOV_EXCL_LINE
491                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
492         }
493
494         if (!ip6tc_commit(handle)) {
495                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
496                 ip6tc_free(handle); //LCOV_EXCL_LINE
497                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
498         }
499
500         ip6tc_free(handle);
501
502         STC_LOGI("Success adding rule");
503         return STC_ERROR_NONE;
504 }
505
506 int ip6tables_add_rule_list(GSList *rule_list)
507 {
508         GSList *list;
509         ip6t_handle_t *handle;
510
511         handle = ip6tc_init(IP6TC_TABLE);
512         if (handle == NULL) {
513                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno));
514                 return STC_ERROR_OPERATION_FAILED;
515         }
516
517         for (list = rule_list; list; list = list->next) {
518                 ip6tables_rule_s *rule = list->data;
519                 const char *chain = rule->chain;
520                 unsigned char entry[SIZE_TOTAL] = {0, };
521                 unsigned char mask[SIZE_TOTAL] = {0, };
522
523                 if (!ip6tc_is_chain(chain, handle)) {
524                         STC_LOGE("chain not present [%s]", ip6tc_strerror(errno));
525                         continue;
526                 }
527
528                 if (__create_entry_data(entry, mask, rule) != 0) {
529                         STC_LOGE("Failed to create entry");
530                         continue;
531                 }
532
533                 if (ip6tc_check_entry(chain, (const ip6t_entry_t *)entry, mask, handle)) {
534                         STC_LOGD("Entry already present");
535                         continue;
536                 }
537
538                 if (!ip6tc_append_entry(chain, (const ip6t_entry_t *)entry, handle)) {
539                         STC_LOGE("ip6tc_append_entry failed [%s]", ip6tc_strerror(errno));
540                         continue;
541                 }
542
543                 STC_LOGD("Append entry [%s : %s]", rule->chain, rule->nfacct_name);
544         }
545
546         if (!ip6tc_commit(handle)) {
547                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno));
548                 ip6tc_free(handle);
549                 return STC_ERROR_OPERATION_FAILED;
550         }
551
552         STC_LOGI("Successed to add rule list");
553         ip6tc_free(handle);
554         return STC_ERROR_NONE;
555 }
556
557
558 int ip6tables_insert_rule(ip6tables_rule_s *rule)
559 {
560         ip6t_handle_t *handle;
561         unsigned char entry[SIZE_TOTAL] = {0, };
562         unsigned char mask[SIZE_TOTAL] = {0, };
563
564         const char *chain = rule->chain;
565
566         if (__create_entry_data(entry, mask, rule) != 0) {
567                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
568                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
569         }
570
571         handle = ip6tc_init(IP6TC_TABLE);
572         if (handle == NULL) {
573                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
574                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
575         }
576
577         if (!ip6tc_is_chain(chain, handle)) {
578                 STC_LOGW("chain not present [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
579                 ip6tc_free(handle); //LCOV_EXCL_LINE
580                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
581         }
582
583         if (ip6tc_check_entry(chain, (const ip6t_entry_t *)entry, mask, handle)) {
584                 STC_LOGW("Entry already present"); //LCOV_EXCL_LINE
585                 ip6tc_free(handle); //LCOV_EXCL_LINE
586                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
587         }
588
589         if (!ip6tc_insert_entry(chain, (const ip6t_entry_t *)entry, IP6TC_INSERT_RULENUM, handle)) {
590                 STC_LOGW("ip6tc_insert_entry failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
591                 ip6tc_free(handle); //LCOV_EXCL_LINE
592                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
593         }
594
595         if (!ip6tc_commit(handle)) {
596                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
597                 ip6tc_free(handle); //LCOV_EXCL_LINE
598                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
599         }
600
601         ip6tc_free(handle);
602
603         STC_LOGI("Success adding rule");
604         return STC_ERROR_NONE;
605 }
606
607 int ip6tables_remove_rule(ip6tables_rule_s *rule)
608 {
609         ip6t_handle_t *handle;
610         unsigned char entry[SIZE_TOTAL] = {0, };
611         unsigned char mask[SIZE_TOTAL] = {0, };
612
613         const char *chain = rule->chain;
614
615         if (__create_entry_data(entry, mask, rule) != 0) {
616                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
617                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
618         }
619
620         handle = ip6tc_init(IP6TC_TABLE);
621         if (handle == NULL) {
622                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
623                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
624         }
625
626         if (!ip6tc_is_chain(chain, handle)) {
627                 STC_LOGW("chain not present [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
628                 ip6tc_free(handle); //LCOV_EXCL_LINE
629                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
630         }
631
632         if (!ip6tc_delete_entry(chain, (const ip6t_entry_t *)entry, mask, handle)) {
633                 STC_LOGW("ip6tc_delete_entry failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
634                 ip6tc_free(handle); //LCOV_EXCL_LINE
635                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
636         }
637
638         if (!ip6tc_commit(handle)) {
639                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
640                 ip6tc_free(handle); //LCOV_EXCL_LINE
641                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
642         }
643
644         ip6tc_free(handle);
645
646         STC_LOGI("Success removing rule");
647         return STC_ERROR_NONE;
648 }
649
650 int ip6tables_remove_rule_list(GSList *rule_list)
651 {
652         GSList *list;
653         ip6t_handle_t *handle;
654
655         handle = ip6tc_init(IP6TC_TABLE);
656         if (handle == NULL) {
657                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno));
658                 return STC_ERROR_OPERATION_FAILED;
659         }
660
661         for (list = rule_list; list; list = list->next) {
662                 ip6tables_rule_s *rule = list->data;
663                 const char *chain = rule->chain;
664                 unsigned char entry[SIZE_TOTAL] = {0, };
665                 unsigned char mask[SIZE_TOTAL] = {0, };
666
667                 if (!ip6tc_is_chain(chain, handle)) {
668                         STC_LOGE("chain not present [%s]", ip6tc_strerror(errno));
669                         continue;
670                 }
671
672                 if (__create_entry_data(entry, mask, rule) != 0) {
673                         STC_LOGE("Failed to create entry");
674                         continue;
675                 }
676
677                 if (!ip6tc_delete_entry(chain, (const ip6t_entry_t *)entry, mask, handle)) {
678                         STC_LOGE("ip6tc_append_entry failed [%s]", ip6tc_strerror(errno));
679                         continue;
680                 }
681
682                 STC_LOGD("Append entry [%s : %s]", rule->chain, rule->nfacct_name);
683         }
684
685         if (!ip6tc_commit(handle)) {
686                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno));
687                 ip6tc_free(handle);
688                 return STC_ERROR_OPERATION_FAILED;
689         }
690
691         STC_LOGI("Successed to remove rule list");
692         ip6tc_free(handle);
693         return STC_ERROR_NONE;
694 }
695
696 int ip6tables_add_chain(const char *chain)
697 {
698         ip6t_handle_t *handle;
699
700         handle = ip6tc_init(IP6TC_TABLE);
701         if (handle == NULL) {
702                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
703                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
704         }
705
706         if (ip6tc_is_chain(chain, handle)) {
707                 STC_LOGW("chain already exists"); //LCOV_EXCL_LINE
708                 ip6tc_free(handle); //LCOV_EXCL_LINE
709                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
710         }
711
712         if (!ip6tc_create_chain(chain, handle)) {
713                 STC_LOGE("Failed to create chaing [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
714                 ip6tc_free(handle); //LCOV_EXCL_LINE
715                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
716         }
717
718         if (!ip6tc_commit(handle)) {
719                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
720                 ip6tc_free(handle); //LCOV_EXCL_LINE
721                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
722         }
723
724         ip6tc_free(handle);
725
726         STC_LOGI("Success adding chain");
727         return 0;
728 }
729
730 int ip6tables_remove_chain(const char *chain)
731 {
732         ip6t_handle_t *handle;
733
734         handle = ip6tc_init(IP6TC_TABLE);
735         if (handle == NULL) {
736                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
737                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
738         }
739
740         if (!ip6tc_is_chain(chain, handle)) {
741                 STC_LOGW("chain not present"); //LCOV_EXCL_LINE
742                 ip6tc_free(handle); //LCOV_EXCL_LINE
743                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
744         }
745
746         ip6tc_flush_entries(chain, handle);
747
748         if (!ip6tc_delete_chain(chain, handle)) {
749                 STC_LOGE("Failed to delete chain [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
750                 ip6tc_free(handle); //LCOV_EXCL_LINE
751                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
752         }
753
754         if (!ip6tc_commit(handle)) {
755                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
756                 ip6tc_free(handle); //LCOV_EXCL_LINE
757                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
758         }
759
760         ip6tc_free(handle);
761
762         STC_LOGI("Success removing chain");
763         return STC_ERROR_NONE;
764 }
765
766 int ip6tables_flush_chain(const char *chain)
767 {
768         ip6t_handle_t *handle;
769
770         handle = ip6tc_init(IP6TC_TABLE);
771         if (handle == NULL) {
772                 STC_LOGE("ip6tc_init failed [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
773                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
774         }
775
776         if (!ip6tc_is_chain(chain, handle)) {
777                 STC_LOGW("chain not present"); //LCOV_EXCL_LINE
778                 ip6tc_free(handle); //LCOV_EXCL_LINE
779                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
780         }
781
782         if(!ip6tc_flush_entries(chain, handle)) {
783                 STC_LOGE("Failed to flush chain [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
784                 ip6tc_free(handle); //LCOV_EXCL_LINE
785                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
786         }
787
788         if (!ip6tc_commit(handle)) {
789                 STC_LOGE("Failed to ip6tc_commit [%s]", ip6tc_strerror(errno)); //LCOV_EXCL_LINE
790                 ip6tc_free(handle); //LCOV_EXCL_LINE
791                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
792         }
793
794         ip6tc_free(handle);
795
796         STC_LOGI("Success removing chain");
797         return STC_ERROR_NONE;
798 }