e43cc0dba6221541e303dc5039f3dafafc8ae03d
[platform/core/connectivity/stc-iptables.git] / src / helper / helper-iptables.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
24 #include <linux/netfilter.h>
25 #include <linux/netfilter/xt_cgroup.h>
26 #include <linux/netfilter/xt_nfacct.h>
27 #include <linux/netfilter/xt_iprange.h>
28 #include <linux/netfilter/xt_NFLOG.h>
29 #include <linux/netfilter_ipv4/ipt_LOG.h>
30
31 #include "stc-iptables-error.h"
32 #include "helper-iptables.h"
33 #include "helper-log.h"
34
35 #define IPT_ALIGN    XT_ALIGN
36 #define IPTC_TABLE   "filter"
37 #define IPTC_TCP     "tcp"
38 #define IPTC_UDP     "udp"
39 #define IPTC_CGROUP  "cgroup"
40 #define IPTC_NFACCT  "nfacct"
41 #define IPTC_IPRANGE "iprange"
42 #define IPTC_LOG     "LOG"
43 #define IPTC_NFLOG   "NFLOG"
44
45 #define IPTC_MASK    "255.255.255.255"
46
47 #define IPTC_INSERT_RULENUM 0
48
49 /* handle */
50 typedef struct xtc_handle            ipt_handle_t;
51
52 /* entry */
53 typedef struct ipt_entry             ipt_entry_t;
54 typedef struct ipt_entry_match       ipt_entry_match_t;
55 typedef struct ipt_entry_target      ipt_entry_target_t;
56
57 /* matches */
58 typedef struct xt_tcp                ipt_tcp_info_t;
59 typedef struct xt_udp                ipt_udp_info_t;
60 typedef struct xt_cgroup_info_v0     ipt_cgroup_info_t;
61 typedef struct xt_nfacct_match_info  ipt_nfacct_info_t;
62 typedef struct xt_iprange_mtinfo     ipt_iprange_info_t;
63
64 /* target */
65 typedef struct ipt_log_info          ipt_log_info_t;
66 typedef struct xt_nflog_info         ipt_nflog_info_t;
67
68 #define SIZE_ENTRY IPT_ALIGN(sizeof(ipt_entry_t))
69 #define SIZE_TCP_MATCH IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(sizeof(ipt_tcp_info_t))
70 #define SIZE_UDP_MATCH IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(sizeof(ipt_udp_info_t))
71 #define SIZE_CGROUP_MATCH IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(sizeof(ipt_cgroup_info_t))
72 #define SIZE_NFACCT_MATCH IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(sizeof(ipt_nfacct_info_t))
73 #define SIZE_IPRANGE_MATCH IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(sizeof(ipt_iprange_info_t))
74 #define SIZE_TARGET IPT_ALIGN(sizeof(ipt_entry_target_t)) + IPT_ALIGN(sizeof(int))
75 #define SIZE_TARGET_LOG IPT_ALIGN(sizeof(ipt_log_info_t))
76 #define SIZE_TARGET_NFLOG IPT_ALIGN(sizeof(ipt_nflog_info_t))
77 #define SIZE_TOTAL SIZE_ENTRY + SIZE_TCP_MATCH + SIZE_UDP_MATCH + SIZE_CGROUP_MATCH \
78                                         + SIZE_NFACCT_MATCH + SIZE_IPRANGE_MATCH + SIZE_TARGET \
79                                         + SIZE_TARGET_LOG + SIZE_TARGET_NFLOG
80
81 static unsigned int __add_match(const char *name, ipt_entry_match_t *start,
82                                                                                 int revision, size_t size, void *data)
83 {
84         ipt_entry_match_t *match = start;
85
86         match->u.match_size = IPT_ALIGN(sizeof(ipt_entry_match_t)) + IPT_ALIGN(size);
87
88         g_strlcpy(match->u.user.name, name, XT_EXTENSION_MAXNAMELEN);
89         memcpy(match->data, data, size);
90         match->u.user.revision = revision;
91
92         return match->u.match_size;
93 }
94
95 static unsigned int __add_target(const char *name, ipt_entry_target_t *start, size_t size, void *data)
96 {
97         ipt_entry_target_t *target = start;
98
99         target->u.target_size = IPT_ALIGN(sizeof(ipt_entry_target_t)) + IPT_ALIGN(size);
100
101         g_strlcpy(target->u.user.name, name, XT_EXTENSION_MAXNAMELEN);
102         memcpy(target->data, data, size);
103
104         return target->u.target_size;
105 }
106
107 static unsigned int __add_iprange_match(iptables_ip_type_e sip_type,
108                 struct in_addr sip1, struct in_addr sip2, iptables_ip_type_e dip_type,
109                 struct in_addr dip1, struct in_addr dip2, ipt_entry_match_t *start)
110 {
111         ipt_iprange_info_t iprange;
112         memset(&iprange, 0, sizeof(ipt_iprange_info_t));
113
114         /* iprange => "--src-range " */
115         if (sip_type == IPTABLES_IP_RANGE) {
116                 memcpy(&(iprange.src_min.in), &sip1, sizeof(struct in_addr));
117                 memcpy(&(iprange.src_max.in), &sip2, sizeof(struct in_addr));
118                 iprange.flags |= IPRANGE_SRC;
119         }
120
121         /* iprange => "--dst-range " */
122         if (dip_type == IPTABLES_IP_RANGE) {
123                 memcpy(&(iprange.dst_min.in), &dip1, sizeof(struct in_addr));
124                 memcpy(&(iprange.dst_max.in), &dip2, sizeof(struct in_addr));
125                 iprange.flags |= IPRANGE_DST;
126         }
127
128         /* match_iprange => "-m iprange" */
129         return __add_match(IPTC_IPRANGE, start, 1, sizeof(ipt_iprange_info_t), &iprange);
130 }
131
132 static void __add_iprange(unsigned char *entry, unsigned int *size_mask,
133                 unsigned int *size_match, iptables_rule_s *rule)
134 {
135         ipt_entry_t *e = (ipt_entry_t *)(entry);
136
137         (*size_match) += __add_iprange_match(rule->s_ip_type,
138                 rule->s_ip1, rule->s_ip2, rule->d_ip_type, rule->d_ip1,
139                 rule->d_ip2, (ipt_entry_match_t *)(e->elems + (*size_match)));
140
141         (*size_mask) += sizeof(ipt_entry_match_t);
142         e->target_offset += SIZE_IPRANGE_MATCH;
143         e->next_offset += SIZE_IPRANGE_MATCH;
144 }
145
146 static unsigned int __add_port_match(iptables_protocol_type_e prot_type,
147                 iptables_port_type_e sport_type, unsigned short sport1, unsigned short sport2,
148                 iptables_port_type_e dport_type, unsigned short dport1, unsigned short dport2,
149                 ipt_entry_match_t *start)
150 {
151         switch (prot_type) {
152         case IPTABLES_PROTOCOL_TCP:
153                 {
154                         ipt_tcp_info_t tcp;
155                         memset(&tcp, 0, sizeof(ipt_tcp_info_t));
156                         switch(sport_type) {
157                         /* --sport 80 */
158                         case IPTABLES_PORT_SINGLE:
159                                 tcp.spts[0] = ntohs(htons(sport1));
160                                 tcp.spts[1] = ntohs(htons(sport1));
161                                 break;
162                         /* --sport 0:59136 */
163                         case IPTABLES_PORT_RANGE:
164                                 tcp.spts[0] = ntohs(htons(sport1));
165                                 tcp.spts[1] = ntohs(htons(sport2));
166                                 break;
167                         default:
168                                 tcp.spts[0] = 0x0000;
169                                 tcp.spts[1] = 0xFFFF;
170                                 break;
171                         }
172                         switch(dport_type) {
173                         /* --dport 80 */
174                         case IPTABLES_PORT_SINGLE:
175                                 tcp.dpts[0] = ntohs(htons(dport1));
176                                 tcp.dpts[1] = ntohs(htons(dport1));
177                                 break;
178                         /* --dport 0:59136 */
179                         case IPTABLES_PORT_RANGE:
180                                 tcp.dpts[0] = ntohs(htons(dport1));
181                                 tcp.dpts[1] = ntohs(htons(dport2));
182                                 break;
183                         default:
184                                 tcp.dpts[0] = 0x0000;
185                                 tcp.dpts[1] = 0xFFFF;
186                                 break;
187                         }
188                         return __add_match(IPTC_TCP, start, 0, sizeof(ipt_tcp_info_t), &tcp);
189                 }
190         case IPTABLES_PROTOCOL_UDP:
191                 {
192                         ipt_udp_info_t udp;
193                         memset(&udp, 0, sizeof(ipt_udp_info_t));
194                         switch(sport_type) {
195                         /* --sport 80 */
196                         case IPTABLES_PORT_SINGLE:
197                                 udp.spts[0] = ntohs(htons(sport1));
198                                 udp.spts[1] = ntohs(htons(sport1));
199                                 break;
200                         /* --sport 0:59136 */
201                         case IPTABLES_PORT_RANGE:
202                                 udp.spts[0] = ntohs(htons(sport1));
203                                 udp.spts[1] = ntohs(htons(sport2));
204                                 break;
205                         default:
206                                 udp.spts[0] = 0x0000;
207                                 udp.spts[1] = 0xFFFF;
208                                 break;
209                         }
210                         switch(dport_type) {
211                         /* --dport 80 */
212                         case IPTABLES_PORT_SINGLE:
213                                 udp.dpts[0] = ntohs(htons(dport1));
214                                 udp.dpts[1] = ntohs(htons(dport1));
215                                 break;
216                         /* --dport 0:59136 */
217                         case IPTABLES_PORT_RANGE:
218                                 udp.dpts[0] = ntohs(htons(dport1));
219                                 udp.dpts[1] = ntohs(htons(dport2));
220                                 break;
221                         default:
222                                 udp.dpts[0] = 0x0000;
223                                 udp.dpts[1] = 0xFFFF;
224                                 break;
225                         }
226                         return __add_match(IPTC_UDP, start, 0, sizeof(ipt_udp_info_t), &udp);
227                 }
228         default:
229                 break;
230         }
231
232         return 0;
233 }
234
235 static void __add_port(unsigned char *entry, unsigned int *size_mask,
236                 unsigned int *size_match, iptables_rule_s *rule, unsigned int match_size)
237 {
238         if ((rule->s_port_type > IPTABLES_PORT_NONE &&
239                 rule->s_port_type <= IPTABLES_PORT_RANGE) ||
240                 (rule->d_port_type > IPTABLES_PORT_NONE &&
241                 rule->d_port_type <= IPTABLES_PORT_RANGE)) {
242
243                 ipt_entry_t *e = (ipt_entry_t *)(entry);
244
245                 (*size_match) += __add_port_match(rule->protocol,
246                         rule->s_port_type, rule->s_port1, rule->s_port2,
247                         rule->d_port_type, rule->d_port1, rule->d_port2,
248                         (ipt_entry_match_t *) (e->elems + (*size_match)));
249
250                 (*size_mask) += sizeof(ipt_entry_match_t);
251                 e->target_offset += match_size;
252                 e->next_offset += match_size;
253         }
254 }
255
256 static unsigned int __add_cgroup_match(unsigned int classid, ipt_entry_match_t *start)
257 {
258         /* cgroup => "--cgroup 0" */
259         ipt_cgroup_info_t cgroup;
260         memset(&cgroup, 0, sizeof(ipt_cgroup_info_t));
261         cgroup.id = classid;
262         /* match_cgroup => "-m cgroup" */
263         return __add_match(IPTC_CGROUP, start, 0, sizeof(ipt_cgroup_info_t), &cgroup);
264 }
265
266 static unsigned int __add_nfacct_match(const char *nfacct_name, ipt_entry_match_t *start)
267 {
268         /* nfacct => "--nfacct_name " */
269         ipt_nfacct_info_t nfacct;
270         memset(&nfacct, 0, sizeof(ipt_nfacct_info_t));
271         g_strlcpy(nfacct.name, nfacct_name, NFACCT_NAME_MAX);
272         /* match_nfacct => "-m nfacct" */
273         return __add_match(IPTC_NFACCT, start, 0, sizeof(ipt_nfacct_info_t), &nfacct);
274 }
275
276 static unsigned int __add_log_target(unsigned char level, const char *prefix,
277                                                 ipt_entry_target_t *start)
278 {
279         /* log => "--log-level --log-prefix" */
280         ipt_log_info_t log;
281         memset(&log, 0, sizeof(ipt_log_info_t));
282         log.level = level;
283         g_strlcpy(log.prefix, prefix, 30);
284         /* target_log */
285         return __add_target(IPTC_LOG, start, sizeof(ipt_log_info_t), &log);
286 }
287
288 static unsigned int __add_nflog_target(unsigned int group, const char *prefix,
289                                                 unsigned int range, unsigned int threshold, ipt_entry_target_t *start)
290 {
291         /* nflog => "--nflog-group --nflog-prefix --nflog-range --nflog-threshold" */
292         ipt_nflog_info_t nflog;
293         memset(&nflog, 0, sizeof(ipt_nflog_info_t));
294         nflog.group = group;
295         g_strlcpy(nflog.prefix, prefix, 64);
296         nflog.len = range;
297         nflog.threshold = threshold;
298         /* target_nflog */
299         return __add_target(IPTC_NFLOG, start, sizeof(ipt_nflog_info_t), &nflog);
300 }
301
302 static int __create_entry_data(unsigned char *entry, unsigned char *mask,
303                                iptables_rule_s *rule)
304 {
305         ipt_entry_t *e = NULL;
306         ipt_entry_target_t *target = NULL;
307         unsigned int size_mask = 0;
308         unsigned int size_match = 0;
309
310         if (!rule->chain) {
311                 STC_LOGE("Invalid parameters"); //LCOV_EXCL_LINE
312                 return STC_ERROR_INVALID_PARAMETER; //LCOV_EXCL_LINE
313         }
314
315         e = (ipt_entry_t *)(entry);
316
317         /* entry size */
318         e->target_offset = SIZE_ENTRY;
319         e->next_offset = SIZE_ENTRY;
320         size_mask = sizeof(ipt_entry_t);
321
322         if (rule->ifname && rule->ifname[0] != '\0') {
323                 switch (rule->direction) {
324                 case IPTABLES_DIRECTION_IN:
325                         /* -i wlan0 */
326                         g_strlcpy(e->ip.iniface, rule->ifname, IFNAMSIZ);
327                         memset(&(e->ip.iniface_mask), 0xFF, IFNAMSIZ);
328                         break;
329                 case IPTABLES_DIRECTION_OUT:
330                         /* -o wlan0 */
331                         g_strlcpy(e->ip.outiface, rule->ifname, IFNAMSIZ);
332                         memset(&(e->ip.outiface_mask), 0xFF, IFNAMSIZ);
333                         break;
334                 default:
335                         STC_LOGE("Invalid parameter"); //LCOV_EXCL_LINE
336                         break; //LCOV_EXCL_LINE
337                 }
338         }
339
340         switch (rule->s_ip_type) {
341         case IPTABLES_IP_SINGLE:
342                 /* -s 102.132.217.5/32 */
343                 e->ip.src.s_addr = rule->s_ip1.s_addr;
344                 inet_pton(AF_INET, IPTC_MASK, &(e->ip.smsk));
345                 break;
346         case IPTABLES_IP_MASK:
347                 /* -s 102.132.217.5/24 */
348                 e->ip.src.s_addr = rule->s_ip1.s_addr;
349                 e->ip.smsk.s_addr = rule->s_ip2.s_addr;
350                 break;
351         default:
352                 break;
353         }
354
355         switch (rule->d_ip_type) {
356         case IPTABLES_IP_SINGLE:
357                 /* -d 102.132.217.5/32 */
358                 e->ip.dst.s_addr = rule->d_ip1.s_addr;
359                 inet_pton(AF_INET, IPTC_MASK, &(e->ip.dmsk));
360                 break;
361         case IPTABLES_IP_MASK:
362                 /* -d 102.132.217.5/24 */
363                 e->ip.dst.s_addr = rule->d_ip1.s_addr;
364                 e->ip.dmsk.s_addr = rule->d_ip2.s_addr;
365                 break;
366         default:
367                 break;
368         }
369
370         if (rule->s_ip_type == IPTABLES_IP_RANGE ||
371                 rule->d_ip_type == IPTABLES_IP_RANGE)
372                 __add_iprange(entry, &size_mask, &size_match, rule);
373
374         /* -p tcp */
375         switch (rule->protocol) {
376         case IPTABLES_PROTOCOL_TCP:
377                 e->ip.proto = IPPROTO_TCP;
378                 __add_port(entry, &size_mask, &size_match, rule, SIZE_TCP_MATCH);
379                 break;
380         case IPTABLES_PROTOCOL_UDP:
381                 e->ip.proto = IPPROTO_UDP;
382                 __add_port(entry, &size_mask, &size_match, rule, SIZE_UDP_MATCH);
383                 break;
384         case IPTABLES_PROTOCOL_ICMP:
385                 e->ip.proto = IPPROTO_ICMP;
386                 break;
387         case IPTABLES_PROTOCOL_ESP:
388                 e->ip.proto = IPPROTO_ESP;
389                 break;
390         case IPTABLES_PROTOCOL_AH:
391                 e->ip.proto = IPPROTO_AH;
392                 break;
393         case IPTABLES_PROTOCOL_SCTP:
394                 e->ip.proto = IPPROTO_SCTP;
395                 break;
396         case IPTABLES_PROTOCOL_MH:
397                 e->ip.proto = IPPROTO_MH;
398                 break;
399         case IPTABLES_PROTOCOL_ALL:
400                 e->ip.proto = 0;
401                 break;
402         default:
403                 e->ip.proto = 0;
404                 break;
405         }
406
407         /* -m cgroup --cgroup 33 */
408         if (rule->classid > 0) {
409                 size_match += __add_cgroup_match(rule->classid,
410                         (ipt_entry_match_t *) (e->elems + size_match));
411                 size_mask += sizeof(ipt_entry_match_t);
412                 e->target_offset += SIZE_CGROUP_MATCH;
413                 e->next_offset += SIZE_CGROUP_MATCH;
414         }
415
416         /* -m nfacct --nfacct-name c2_1_33_seth_w0 */
417         if (rule->nfacct_name && rule->nfacct_name[0] != '\0') {
418                 size_match += __add_nfacct_match(rule->nfacct_name,
419                         (ipt_entry_match_t *) (e->elems + size_match));
420                 size_mask += sizeof(ipt_entry_match_t);
421                 e->target_offset += SIZE_NFACCT_MATCH;
422                 e->next_offset += SIZE_NFACCT_MATCH;
423         }
424
425         /* target => "-j ACCEPT" */
426         target = (ipt_entry_target_t *) (e->elems + size_match);
427         switch (rule->target_type) {
428         case IPTABLES_ACTION_LOG:
429                 e->next_offset += __add_log_target(rule->log_level, rule->log_prefix, target);
430                 break;
431         case IPTABLES_ACTION_NFLOG:
432                 e->next_offset += __add_nflog_target(rule->nflog_group,
433                         rule->nflog_prefix, rule->nflog_range, rule->nflog_threshold, target);
434                 break;
435         default:
436                 target->u.target_size = SIZE_TARGET;
437                 if (rule->target && rule->target[0] != '\0')
438                         g_strlcpy(target->u.user.name, rule->target, XT_EXTENSION_MAXNAMELEN);
439                 e->next_offset += SIZE_TARGET;
440                 break;
441         }
442
443         memset(mask, 0xFF, size_mask);
444
445         return STC_ERROR_NONE;
446 }
447
448 int iptables_add_rule(iptables_rule_s *rule)
449 {
450         ipt_handle_t *handle;
451         unsigned char entry[SIZE_TOTAL] = {0, };
452         unsigned char mask[SIZE_TOTAL] = {0, };
453
454         const char *chain = rule->chain;
455
456         if (__create_entry_data(entry, mask, rule) != 0) {
457                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
458                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
459         }
460
461         handle = iptc_init(IPTC_TABLE);
462         if (handle == NULL) {
463                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
464                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
465         }
466
467         if (!iptc_is_chain(chain, handle)) {
468                 STC_LOGW("chain not present [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
469                 iptc_free(handle); //LCOV_EXCL_LINE
470                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
471         }
472
473         if (iptc_check_entry(chain, (const ipt_entry_t *)entry, mask, handle)) {
474                 STC_LOGW("Entry already present"); //LCOV_EXCL_LINE
475                 iptc_free(handle); //LCOV_EXCL_LINE
476                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
477         }
478
479         if (!iptc_append_entry(chain, (const ipt_entry_t *)entry, handle)) {
480                 STC_LOGW("iptc_append_entry failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
481                 iptc_free(handle); //LCOV_EXCL_LINE
482                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
483         }
484
485         if (!iptc_commit(handle)) {
486                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
487                 iptc_free(handle); //LCOV_EXCL_LINE
488                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
489         }
490
491         iptc_free(handle);
492
493         STC_LOGI("Success adding rule");
494         return STC_ERROR_NONE;
495 }
496
497 int iptables_insert_rule(iptables_rule_s *rule)
498 {
499         ipt_handle_t *handle;
500         unsigned char entry[SIZE_TOTAL] = {0, };
501         unsigned char mask[SIZE_TOTAL] = {0, };
502
503         const char *chain = rule->chain;
504
505         if (__create_entry_data(entry, mask, rule) != 0) {
506                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
507                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
508         }
509
510         handle = iptc_init(IPTC_TABLE);
511         if (handle == NULL) {
512                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
513                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
514         }
515
516         if (!iptc_is_chain(chain, handle)) {
517                 STC_LOGW("chain not present [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
518                 iptc_free(handle); //LCOV_EXCL_LINE
519                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
520         }
521
522         if (iptc_check_entry(chain, (const ipt_entry_t *)entry, mask, handle)) {
523                 STC_LOGW("Entry already present"); //LCOV_EXCL_LINE
524                 iptc_free(handle); //LCOV_EXCL_LINE
525                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
526         }
527
528         if (!iptc_insert_entry(chain, (const ipt_entry_t *)entry, IPTC_INSERT_RULENUM, handle)) {
529                 STC_LOGW("iptc_insert_entry failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
530                 iptc_free(handle); //LCOV_EXCL_LINE
531                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
532         }
533
534         if (!iptc_commit(handle)) {
535                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
536                 iptc_free(handle); //LCOV_EXCL_LINE
537                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
538         }
539
540         iptc_free(handle);
541
542         STC_LOGI("Success inserting rule");
543         return STC_ERROR_NONE;
544 }
545
546 int iptables_remove_rule(iptables_rule_s *rule)
547 {
548         ipt_handle_t *handle;
549         unsigned char entry[SIZE_TOTAL] = {0, };
550         unsigned char mask[SIZE_TOTAL] = {0, };
551
552         const char *chain = rule->chain;
553
554         if (__create_entry_data(entry, mask, rule) != 0) {
555                 STC_LOGE("Failed to create entry"); //LCOV_EXCL_LINE
556                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
557         }
558
559         handle = iptc_init(IPTC_TABLE);
560         if (handle == NULL) {
561                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
562                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
563         }
564
565         if (!iptc_is_chain(chain, handle)) {
566                 STC_LOGW("chain not present [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
567                 iptc_free(handle); //LCOV_EXCL_LINE
568                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
569         }
570
571         if (!iptc_delete_entry(chain, (const ipt_entry_t *)entry, mask, handle)) {
572                 STC_LOGW("iptc_delete_entry failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
573                 iptc_free(handle); //LCOV_EXCL_LINE
574                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
575         }
576
577         if (!iptc_commit(handle)) {
578                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
579                 iptc_free(handle); //LCOV_EXCL_LINE
580                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
581         }
582
583         iptc_free(handle);
584
585         STC_LOGI("Success removing rule");
586         return STC_ERROR_NONE;
587 }
588
589 int iptables_add_chain(const char *chain)
590 {
591         ipt_handle_t *handle;
592
593         handle = iptc_init(IPTC_TABLE);
594         if (handle == NULL) {
595                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
596                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
597         }
598
599         if (iptc_is_chain(chain, handle)) {
600                 STC_LOGW("chain already exists"); //LCOV_EXCL_LINE
601                 iptc_free(handle); //LCOV_EXCL_LINE
602                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
603         }
604
605         if (!iptc_create_chain(chain, handle)) {
606                 STC_LOGE("Failed to create chaing [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
607                 iptc_free(handle); //LCOV_EXCL_LINE
608                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
609         }
610
611         if (!iptc_commit(handle)) {
612                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
613                 iptc_free(handle); //LCOV_EXCL_LINE
614                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
615         }
616
617         iptc_free(handle);
618
619         STC_LOGI("Success adding chain");
620         return 0;
621 }
622
623 int iptables_remove_chain(const char *chain)
624 {
625         ipt_handle_t *handle;
626
627         handle = iptc_init(IPTC_TABLE);
628         if (handle == NULL) {
629                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
630                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
631         }
632
633         if (!iptc_is_chain(chain, handle)) {
634                 STC_LOGW("chain not present"); //LCOV_EXCL_LINE
635                 iptc_free(handle); //LCOV_EXCL_LINE
636                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
637         }
638
639         iptc_flush_entries(chain, handle);
640
641         if (!iptc_delete_chain(chain, handle)) {
642                 STC_LOGE("Failed to delete chain [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
643                 iptc_free(handle); //LCOV_EXCL_LINE
644                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
645         }
646
647         if (!iptc_commit(handle)) {
648                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
649                 iptc_free(handle); //LCOV_EXCL_LINE
650                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
651         }
652
653         iptc_free(handle);
654
655         STC_LOGI("Success removing chain");
656         return STC_ERROR_NONE;
657 }
658
659 int iptables_flush_chain(const char *chain)
660 {
661         ipt_handle_t *handle;
662
663         handle = iptc_init(IPTC_TABLE);
664         if (handle == NULL) {
665                 STC_LOGE("iptc_init failed [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
666                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
667         }
668
669         if (!iptc_is_chain(chain, handle)) {
670                 STC_LOGW("chain not present"); //LCOV_EXCL_LINE
671                 iptc_free(handle); //LCOV_EXCL_LINE
672                 return STC_ERROR_NONE; //LCOV_EXCL_LINE
673         }
674
675         if (!iptc_flush_entries(chain, handle)) {
676                 STC_LOGE("Failed to flush chain [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
677                 iptc_free(handle); //LCOV_EXCL_LINE
678                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
679         }
680
681         if (!iptc_commit(handle)) {
682                 STC_LOGE("Failed to iptc_commit [%s]", iptc_strerror(errno)); //LCOV_EXCL_LINE
683                 iptc_free(handle); //LCOV_EXCL_LINE
684                 return STC_ERROR_OPERATION_FAILED; //LCOV_EXCL_LINE
685         }
686
687         iptc_free(handle);
688
689         STC_LOGI("Success flushing chain");
690         return STC_ERROR_NONE;
691 }