Merge "Return errors to caller" into tizen_5.5
[platform/core/connectivity/stc-manager.git] / src / helper / helper-nfacct-rule.c
index b46b3a4..ff703d3 100755 (executable)
@@ -26,6 +26,7 @@
 
 #include "counter.h"
 #include "helper-nfacct-rule.h"
+#include "helper-iptables.h"
 
 #include "configure_stub.h"
 
@@ -37,8 +38,8 @@
 #define INSERT "-I"
 
 #define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
-#define REJECT_RULE " -j REJECT"
-#define ACCEPT_RULE " -j ACCEPT"
+#define REJECT_RULE "REJECT"
+#define ACCEPT_RULE "ACCEPT"
 #define OUT_RULE "OUTPUT"
 #define IN_RULE "INPUT"
 #define FORWARD_RULE "FORWARD"
 #define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s"
 #define RULE_APP_IN "%s -w %s INPUT -i %s -m cgroup --cgroup %u %s %s"
 
-
 /* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
 
 #define RULE_IFACE_OUT "%s -w %s %s -o %s %s %s"
 #define RULE_IFACE_IN "%s -w %s %s -i %s %s  %s"
 
-
 #define NFNL_SUBSYS_ACCT                7
 #define BUF_SIZE_FOR_ERR 100
 
@@ -109,7 +108,7 @@ static void add_string_attr(struct genl *req, const char *str, int type)
        add_value_attr(req, str, strlen(str) + 1, type);
 }
 
-static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
+static void add_uint64_attr(struct genl *req, const long long unsigned int v, int type)
 {
        add_value_attr(req, &v, sizeof(v), type);
 }
@@ -133,36 +132,49 @@ static stc_error_e send_nfacct_request(int sock, struct genl *req)
 
 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
 {
-       struct genl req;
-
-       prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
-       add_string_attr(&req, counter->name, NFACCT_NAME);
+       int ret = STC_ERROR_NONE;
+       struct genl *req = MALLOC0(struct genl, 1);
+       if (req == NULL) {
+               STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
+               return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
+       }
 
-       STC_LOGD("counter name %s", counter->name);
+       prepare_netlink_msg(req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
+       add_string_attr(req, counter->name, NFACCT_NAME);
 
        /* padding */
-       add_uint64_attr(&req, 0, NFACCT_PKTS);
-       add_uint64_attr(&req, 0, NFACCT_BYTES);
+       add_uint64_attr(req, 0, NFACCT_PKTS);
+       add_uint64_attr(req, 0, NFACCT_BYTES);
+       //LCOV_EXCL_START
        if (counter->quota) {
-               STC_LOGD("quota bytes %"PRId64, counter->quota);
+               STC_LOGD("quota bytes %lld", counter->quota);
 
-               add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES),
+               add_uint32_attr(req, htobe32(NFACCT_F_QUOTA_BYTES),
                                NFACCT_FLAGS);
-               add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA);
+               add_uint64_attr(req, htobe64(counter->quota), NFACCT_QUOTA);
        }
+       //LCOV_EXCL_STOP
 
-       return send_nfacct_request(counter->carg->sock, &req);
+       ret = send_nfacct_request(counter->carg->sock, req);
+       FREE(req);
+       return ret;
 }
 
 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
 {
-       struct genl req;
+       int ret = STC_ERROR_NONE;
+       struct genl *req = MALLOC0(struct genl, 1);
+       if (req == NULL) {
+               STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
+               return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
+       }
 
-       STC_LOGD("send remove request for %s", counter->name);
+       prepare_netlink_msg(req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
+       add_string_attr(req, counter->name, NFACCT_NAME);
 
-       prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
-       add_string_attr(&req, counter->name, NFACCT_NAME);
-       return send_nfacct_request(counter->carg->sock, &req);
+       ret = send_nfacct_request(counter->carg->sock, req);
+       FREE(req);
+       return ret;
 }
 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
 
@@ -171,22 +183,29 @@ static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
                                            const char *name,
                                            int mask, int filter)
 {
-       struct genl req;
+       int ret = STC_ERROR_NONE;
        struct nlattr *na;
        int flag = !name ? NLM_F_DUMP : 0;
-       prepare_netlink_msg(&req, get_type,
-                           flag);
+       struct genl *req = MALLOC0(struct genl, 1);
+       if (req == NULL) {
+               STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
+               return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
+       }
+
+       prepare_netlink_msg(req, get_type, flag);
        /* due we don't get counter with quota any where else,
         * here we will request just counters by default */
        if (name)
-               add_string_attr(&req, name, NFACCT_NAME);
+               add_string_attr(req, name, NFACCT_NAME);
 
-       na = start_nest_attr(&req, NFACCT_FILTER);
-       add_uint32_attr(&req, htonl(mask),
-                       NFACCT_FILTER_ATTR_MASK);
-       add_uint32_attr(&req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
-       end_nest_attr(&req, na);
-       return send_nfacct_request(carg->sock, &req);
+       na = start_nest_attr(req, NFACCT_FILTER);
+       add_uint32_attr(req, htonl(mask), NFACCT_FILTER_ATTR_MASK);
+       add_uint32_attr(req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
+       end_nest_attr(req, na);
+
+       ret = send_nfacct_request(carg->sock, req);
+       FREE(req);
+       return ret;
 }
 
 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
@@ -204,7 +223,7 @@ stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
                                        NFACCT_F_QUOTA_BYTES);
 }
 
-stc_error_e nfacct_send_get_all(struct counter_arg *carg)
+API stc_error_e nfacct_send_get_all(struct counter_arg *carg)
 {
        /* get and reset everything, used when quiting */
        return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
@@ -230,10 +249,10 @@ static nfacct_rule_direction convert_to_iotype(int type)
 static stc_iface_type_e convert_to_iftype(int type)
 {
        return (type < STC_IFACE_LAST_ELEM &&
-               type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
+                       type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
 }
 
-bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
+API bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
 {
        char *iftype_part;
        char *classid_part;
@@ -254,15 +273,27 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
        case 'r':
                cnt->intend  = NFACCT_BLOCK;
                break;
-       case 't':
-               cnt->intend  = NFACCT_TETH_COUNTER;
+       case 'a':
+               cnt->intend  = NFACCT_ALLOW;
                break;
+       case 't':
+               cnt->intend  = NFACCT_TETH_COUNTER; //LCOV_EXCL_LINE
+               break; //LCOV_EXCL_LINE
        default:
                return false;
        }
 
        STRING_SAVE_COPY(cnt->name, cnt_name);
 
+#if 0
+       /* ========================================================
+        * NOTE:-
+        * Below parsing for tethering case is not in use
+        * stc-manager needs to ignore this for NFACCT_TETH_COUNTER
+        * this is disbaled for future use.
+        * =======================================================*/
+
+       //LCOV_EXCL_START
        if (cnt->intend == NFACCT_TETH_COUNTER) {
                char ifname_buf[MAX_IFACE_LENGTH];
                int ifname_len;
@@ -278,15 +309,15 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
                iface = get_iftype_by_name(ifname_buf);
                /* check first part is it datacall */
                if (iface == STC_IFACE_DATACALL) {
-                       strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
+                       strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
                        cnt->iotype = NFACCT_COUNTER_IN;
                } else {
                        /* +1, due : symbol and till the end of cnt_name */
-                       strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH);
+                       strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH - 1);
                        iface = get_iftype_by_name(ifname_buf);
                        if (iface == STC_IFACE_DATACALL) {
                                cnt->iotype = NFACCT_COUNTER_OUT;
-                               strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
+                               strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
                        }
                }
 
@@ -298,6 +329,8 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
                cnt->classid = STC_TETHERING_APP_CLASSID;
                return true;
        }
+       //LCOV_EXCL_STOP
+#endif
 
        io_part = strtok_r(name, "_", &save_ptr);
        if (io_part != NULL)
@@ -363,7 +396,7 @@ next:
                params->post_eval_attr(carg);
 }
 
-netlink_serialization_command *
+API netlink_serialization_command *
 netlink_create_command(struct netlink_serialization_params *params)
 {
        static netlink_serialization_command command = {0,};
@@ -372,287 +405,179 @@ netlink_create_command(struct netlink_serialization_params *params)
        return &command;
 }
 
-static unsigned int get_args_number(const char *cmd_buf)
+static char *get_iptables_cmd(const nfacct_rule_action action)
 {
-       char *str;
-       unsigned int count = 0;
+       if (action == NFACCT_ACTION_APPEND)
+               return APPEND;
+       else if (action == NFACCT_ACTION_DELETE)
+               return DELETE;
+       else if (action == NFACCT_ACTION_INSERT)
+               return INSERT;
 
-       for (str = (char *)cmd_buf; *str != '\0'; ++str) {
-               if (*str == ' ')
-                       ++count;
-       }
-       return count;
+       return "";
 }
 
-static void wait_for_rule_cmd(pid_t pid)
-{
-       int status;
-       pid_t ret_pid;
-       char buf[BUF_SIZE_FOR_ERR] = { 0 };
-
-       if (!pid || pid == -1) {
-               STC_LOGD("no need to wait");
-               return;
-       }
+static char *get_iptables_chain(uint32_t classid,
+                               const nfacct_rule_direction iotype,
+                               const stc_app_state_e app_state,
+                               const nfacct_rule_intend intend)
+{
+       if (iotype == NFACCT_COUNTER_IN) {
+               if (intend == NFACCT_COUNTER ||
+                       intend == NFACCT_TETH_COUNTER) {
+                       if (app_state == STC_APP_STATE_FOREGROUND)
+                               return STC_IN_FG_CHAIN;
+                       else
+                               return STC_IN_BG_CHAIN;
+               } else if (intend == NFACCT_ALLOW ||
+                               intend == NFACCT_TETH_ALLOW) {
+                       return STC_IN_ACCEPT_CHAIN;
+               } else {
+                       if (classid == STC_BACKGROUND_APP_CLASSID)
+                               return STC_IN_BG_DROP_CHAIN;
+                       else
+                               return STC_IN_DROP_CHAIN;
+               }
+       } else if (iotype == NFACCT_COUNTER_OUT) {
+               if (intend == NFACCT_COUNTER ||
+                       intend == NFACCT_TETH_COUNTER) {
+                       if (app_state == STC_APP_STATE_FOREGROUND)
+                               return STC_OUT_FG_CHAIN;
+                       else
+                               return STC_OUT_BG_CHAIN;
+               } else if (intend == NFACCT_ALLOW ||
+                               intend == NFACCT_TETH_ALLOW) {
+                       return STC_OUT_ACCEPT_CHAIN;
+               } else {
+                       if (classid == STC_BACKGROUND_APP_CLASSID)
+                               return STC_OUT_BG_DROP_CHAIN;
+                       else
+                               return STC_OUT_DROP_CHAIN;
+               }
+       } else if (iotype == NFACCT_COUNTER_FORWARD)
+               return STC_FRWD_CHAIN;
 
-       ret_pid = waitpid(pid, &status, 0);
-       if (ret_pid < 0)
-               STC_LOGD("can't wait for a pid %d %d %s", pid, status,
-                        strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
+       return "";
 }
 
-static char* get_cmd_pos(const char *cmd_buf)
+static char *get_iptables_jump(const nfacct_rule_jump jump)
 {
-       char *cmd_pos = strstr(cmd_buf, APPEND);
-       if (!cmd_pos)
-               cmd_pos = strstr(cmd_buf, INSERT);
+       if (jump == NFACCT_JUMP_ACCEPT)
+               return ACCEPT_RULE;
+       else if (jump == NFACCT_JUMP_REJECT)
+               return REJECT_RULE;
 
-       return cmd_pos;
+       return "";
 }
 
-static bool is_rule_present(const char *cmd_buf)
+/*
+static char *choose_iftype_name(nfacct_rule_s *rule)
 {
-       size_t buf_len;
-       char *exec_buf;
-       char *cmd_pos = get_cmd_pos(cmd_buf);
-       bool ret = false;
-       if (!cmd_pos)
-               return false;
-
-       buf_len = strlen(cmd_buf) + 1;
-       exec_buf = (char *)malloc(buf_len);
-       if (!exec_buf)
-               return false;
-
-       strncpy(exec_buf, cmd_buf, buf_len);
-       strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
-               sizeof(IPTABLES_CHECK) - 1);
-
-       STC_LOGD("check rule %s", exec_buf);
-
-       ret = system(exec_buf) == 0;
-       free(exec_buf);
-       return ret;
+       return strlen(rule->ifname) != 0 ? rule->ifname :
+               get_iftype_name(rule->iftype);
 }
+*/
 
-stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
+static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
 {
-       const size_t args_number = get_args_number(cmd_buf);
-       *cmd_pid = 0;
-
-       ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
-
-       pid_t pid = fork();
-
-       if (pid == 0) {
-               char *cmd;
-               unsigned int i;
-               char *args[args_number + 2];
-               int ret;
-               char *save_ptr = NULL;
-               char buf[BUF_SIZE_FOR_ERR] = { 0 };
-
-               STC_LOGD("executing iptables cmd %s in forked process",
-                        cmd_buf);
+       stc_error_e ret = STC_ERROR_NONE;
+       iptables_ip_type_e iptype;
+       iptables_rule_s iptables_rule;
+       memset(&iptables_rule, 0, sizeof(iptables_rule_s));
+
+       iptables_rule.nfacct_name = g_strdup(rule->name);
+       iptables_rule.ifname = g_strdup(rule->ifname);
+       iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
+
+       /* In case of tehering rules use chain 'STC_TETHER' */
+       if (rule->intend == NFACCT_TETH_COUNTER ||
+                       rule->intend == NFACCT_TETH_ALLOW ||
+                       rule->intend == NFACCT_TETH_BLOCK)
+               iptables_rule.chain = g_strdup(STC_TETHER_CHAIN);
+       else
+               iptables_rule.chain = g_strdup(get_iptables_chain(rule->classid,
+                                                               rule->iotype, rule->app_state, rule->intend));
 
-               if (is_rule_present(cmd_buf)) {
-                       STC_LOGD("Rule %s already present", cmd_buf);
-                       exit(0);
+       if (rule->classid < STC_RESERVED_CLASSID_MAX)
+               iptables_rule.classid = STC_UNKNOWN_CLASSID;
+       else
+               iptables_rule.classid = rule->classid;
+       iptables_rule.direction = (rule->iotype & NFACCT_COUNTER_IN) ?
+                                       IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
+       iptype = (iptables_ip_type_e)rule->iptype;
+
+       /* specify the ip range type for source and destination */
+       iptables_rule.s_iprange_type = rule->src_iprange_type;
+       iptables_rule.d_iprange_type = rule->dst_iprange_type;
+
+       /* specify source and destination ip address if any */
+       if (rule->src_ip1) {
+               if (!inet_aton(rule->src_ip1, &iptables_rule.s_ip1)) {
+                       ret = STC_ERROR_INVALID_PARAMETER;
+                       goto free;
                }
+       }
 
-               args[0] = "iptables";
-               cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
-               if (cmd == NULL) {
-                       STC_LOGE("no arguments");
-                       exit(-EINVAL);
+       if (rule->src_ip2) {
+               if (!inet_aton(rule->src_ip2, &iptables_rule.s_ip2)) {
+                       ret = STC_ERROR_INVALID_PARAMETER;
+                       goto free;
                }
-
-               for (i = 1; i <= args_number; ++i)
-                       args[i] = strtok_r(NULL, " ", &save_ptr);
-
-               args[i] = NULL;
-
-               ret = execv(cmd, args);
-               if (ret)
-                       STC_LOGE("Can't execute %s: %s",
-                                cmd_buf, strerror_r(errno, buf,
-                                                    BUF_SIZE_FOR_ERR));
-               exit(ret);
        }
 
-       *cmd_pid = pid;
-       return STC_ERROR_NONE;
-}
-
-stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
-{
-       const size_t args_number = get_args_number(cmd_buf);
-       *cmd_pid = 0;
-
-       ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
-
-       pid_t pid = fork();
-
-       if (pid == 0) {
-               char *cmd;
-               unsigned int i;
-               char *args[args_number + 2];
-               int ret;
-               char *save_ptr = NULL;
-               char buf[BUF_SIZE_FOR_ERR] = { 0 };
-
-               STC_LOGD("executing ip6tables cmd %s in forked process",
-                        cmd_buf);
-
-               if (is_rule_present(cmd_buf)) {
-                       STC_LOGD("Rule %s already present", cmd_buf);
-                       exit(0);
+       if (rule->dst_ip1) {
+               if (!inet_aton(rule->dst_ip1, &iptables_rule.d_ip1)) {
+                       ret = STC_ERROR_INVALID_PARAMETER;
+                       goto free;
                }
+       }
 
-               args[0] = "ip6tables";
-               cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
-               if (cmd == NULL) {
-                       STC_LOGE("no arguments");
-                       exit(-EINVAL);
+       if (rule->dst_ip2) {
+               if (!inet_aton(rule->dst_ip2, &iptables_rule.d_ip2)) {
+                       ret = STC_ERROR_INVALID_PARAMETER;
+                       goto free;
                }
-
-               for (i = 1; i <= args_number; ++i)
-                       args[i] = strtok_r(NULL, " ", &save_ptr);
-
-               args[i] = NULL;
-
-               ret = execv(cmd, args);
-               if (ret)
-                       STC_LOGE("Can't execute %s: %s",
-                                cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
-               exit(ret);
        }
 
-       *cmd_pid = pid;
-       return STC_ERROR_NONE;
-}
-
-static char *choose_iftype_name(nfacct_rule_s *rule)
-{
-       return strlen(rule->ifname) != 0 ? rule->ifname :
-               get_iftype_name(rule->iftype);
-}
-
-static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd,
-                                 const char *chain, const char *nfacct,
-                                 const char *jump, char *iftype_name,
-                                 pid_t *pid)
-{
-       char block_buf[MAX_PATH_LENGTH];
-       int ret;
-
-       ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
-                        "Invalid network interface name argument");
-
-       /* iptables rule */
-       ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd, chain,
-                     iftype_name, nfacct, jump);
-       ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
-                        "Not enough buffer");
-       exec_iptables_cmd(block_buf, pid);
-       wait_for_rule_cmd(*pid);
-
-       /* ip6tables rule */
-       ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd, chain,
-                     iftype_name, nfacct, jump);
-       ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
-                        "Not enough buffer");
-       ret = exec_ip6tables_cmd(block_buf, pid);
-       wait_for_rule_cmd(*pid);
-
-       return ret;
-}
+       if (rule->action == NFACCT_ACTION_DELETE) {
+               /* delete interface rule */
+               ret = iptables_remove(&iptables_rule, iptype);
+       } else {
+               /* add interface rule */
+               ret = iptables_add(&iptables_rule, iptype);
+       }
 
-static stc_error_e exec_app_cmd(const char *pattern, const char *cmd,
-                               const char *nfacct, const char *jump,
-                               const uint32_t classid, char *iftype_name,
-                               pid_t *pid)
-{
-       char block_buf[MAX_PATH_LENGTH];
-       int ret;
-       ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
-                        "Invalid network interface name argument");
-
-       /* iptables rules */
-       ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd,
-                     iftype_name, classid, nfacct, jump);
-       ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
-                        "Not enough buffer");
-       exec_iptables_cmd(block_buf, pid);
-       wait_for_rule_cmd(*pid);
-
-       /* ip6tables rules */
-       ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd,
-                     iftype_name, classid, nfacct, jump);
-       ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
-                        "Not enough buffer");
-       ret = exec_ip6tables_cmd(block_buf, pid);
-       wait_for_rule_cmd(*pid);
+free:
+       g_free(iptables_rule.nfacct_name);
+       g_free(iptables_rule.ifname);
+       g_free(iptables_rule.target);
+       g_free(iptables_rule.chain);
 
        return ret;
 }
 
-static char *get_iptables_cmd(const nfacct_rule_action action)
+static stc_error_e produce_app_rule(nfacct_rule_s *rule)
 {
-       if (action == NFACCT_ACTION_APPEND)
-               return APPEND;
-       else if (action == NFACCT_ACTION_DELETE)
-               return DELETE;
-       else if (action == NFACCT_ACTION_INSERT)
-               return INSERT;
-
-       return "";
-}
-
-static char *get_iptables_chain(const nfacct_rule_direction iotype)
-{
-       if (iotype == NFACCT_COUNTER_IN)
-               return IN_RULE;
-       else if (iotype == NFACCT_COUNTER_OUT)
-               return OUT_RULE;
+       if (rule == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
 
-       return "";
-}
-
-static char *get_iptables_jump(const nfacct_rule_jump jump)
-{
-       if (jump == NFACCT_JUMP_ACCEPT)
-               return ACCEPT_RULE;
-       else if (jump == NFACCT_JUMP_REJECT)
-               return REJECT_RULE;
-
-       return "";
-}
-
-static stc_error_e produce_app_rule(nfacct_rule_s *rule,
-                                   const int64_t send_limit,
-                                   const int64_t rcv_limit,
-                                   const nfacct_rule_action action,
-                                   const nfacct_rule_jump jump,
-                                   const nfacct_rule_direction iotype)
-{
-       char *set_cmd = get_iptables_cmd(action);
-       char *jump_cmd = get_iptables_jump(jump);
+       char *set_cmd = get_iptables_cmd(rule->action);
+       char *jump_cmd = get_iptables_jump(rule->jump);
        char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
-               3*MAX_DEC_SIZE(int) + 4];
+               3*MAX_DEC_SIZE(int) + 4 + 1];
        stc_error_e ret = STC_ERROR_NONE;
-       pid_t pid = 0;
+       uint32_t classid = rule->classid;
 
        /* income part */
-       if (iotype & NFACCT_COUNTER_IN) {
-               rule->quota = rcv_limit;
+       if (rule->iotype & NFACCT_COUNTER_IN) {
+               rule->quota = rule->rcv_limit;
                rule->iotype = NFACCT_COUNTER_IN;
                generate_counter_name(rule);
 
                /* to support quated counter we need nfacct,
                 *      don't use it in case of just block without a limit
                 *      iow, send_limit = 0 and rcv_limit 0 */
-               if (action != NFACCT_ACTION_DELETE) {
+               if (rule->action != NFACCT_ACTION_DELETE) {
                        ret = nfacct_send_del(rule);
                        ret_value_msg_if(ret != STC_ERROR_NONE, ret,
                                         "can't del quota counter");
@@ -670,16 +595,30 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule,
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enought buffer");
 
-               ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
-                                  rule->classid, choose_iftype_name(rule),
-                                  &pid);
+               /* cgroup extention on FORWARD chain are not allowed
+                * remove classid info in case of tethering rules */
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK) {
+                       classid = rule->classid;
+                       rule->classid = 0;
+               }
+
+               ret = exec_iptables_cmd(rule);
+
+               /* restore the classid info in case of tethering rule */
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK)
+                       rule->classid = classid;
+
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for ingress"
                                 " traffic, for classid %u, cmd %s, j %s",
                                 rule->classid, set_cmd, jump_cmd);
 
                /* remove in any case */
-               if (action == NFACCT_ACTION_DELETE) {
+               if (rule->action == NFACCT_ACTION_DELETE) {
                        /* TODO here and everywhere should be not just a del,
                         *      here should be get counted value and than
                         *      set new counter with that value, but it's minor issue,
@@ -694,12 +633,12 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule,
                }
        }
 
-       if (iotype & NFACCT_COUNTER_OUT) {
+       if (rule->iotype & NFACCT_COUNTER_OUT) {
                /* outcome part */
                rule->iotype = NFACCT_COUNTER_OUT;
-               rule->quota = send_limit;
+               rule->quota = rule->send_limit;
                generate_counter_name(rule);
-               if (action != NFACCT_ACTION_DELETE) {
+               if (rule->action != NFACCT_ACTION_DELETE) {
                        ret = nfacct_send_del(rule);
                        ret_value_msg_if(ret != STC_ERROR_NONE, ret,
                                         "can't del quota counter");
@@ -715,14 +654,29 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule,
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enought buffer");
 
-               ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
-                                  rule->classid, choose_iftype_name(rule),
-                                  &pid);
+               /* cgroup extention on FORWARD chain are not allowed
+                * remove classid info in case of tethering rules */
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK) {
+                       classid = rule->classid;
+                       rule->classid = 0;
+               }
+
+               ret = exec_iptables_cmd(rule);
+
+               /* restore the classid info in case of tethering rule */
+               if (rule->intend == NFACCT_TETH_COUNTER ||
+                               rule->intend == NFACCT_TETH_ALLOW ||
+                               rule->intend == NFACCT_TETH_BLOCK)
+                       rule->classid = classid;
+
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for engress"
                                 " traffic, for classid %u, cmd %s, j %s",
                                 rule->classid, set_cmd, jump_cmd);
-               if (action == NFACCT_ACTION_DELETE) {
+
+               if (rule->action == NFACCT_ACTION_DELETE) {
                        rule->iptables_rule = nfacct_send_del;
                        /* not effective, it's better to replace
                         * set_finalize_flag by set_property,
@@ -738,27 +692,24 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule,
        return STC_ERROR_NONE;
 }
 
-static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
-                                     const int64_t send_limit,
-                                     const int64_t rcv_limit,
-                                     const nfacct_rule_action action,
-                                     const nfacct_rule_jump jump,
-                                     const nfacct_rule_direction iotype)
+static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
 {
-       char *set_cmd = get_iptables_cmd(action);
-       char *jump_cmd = get_iptables_jump(jump);
+       if (rule == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       char *set_cmd = get_iptables_cmd(rule->action);
+       char *jump_cmd = get_iptables_jump(rule->jump);
        char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
-               3*MAX_DEC_SIZE(int) + 4];
+               3*MAX_DEC_SIZE(int) + 4 + 1];
        stc_error_e ret;
-       pid_t pid = 0;
 
-       if (iotype & NFACCT_COUNTER_IN) {
+       if (rule->iotype & NFACCT_COUNTER_IN) {
                /* income part */
                rule->iotype = NFACCT_COUNTER_IN;
-               rule->quota = rcv_limit;
+               rule->quota = rule->rcv_limit;
                generate_counter_name(rule);
 
-               if (action != NFACCT_ACTION_DELETE) {
+               if (rule->action != NFACCT_ACTION_DELETE) {
                        /* send delete comman in case of creation,
                         * because nfacct doesn't reset value for nfacct quota
                         * in case of quota existing */
@@ -777,22 +728,22 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enought buffer");
 
-               ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
-                                    get_iptables_chain(rule->iotype),
-                                    nfacct_buf, jump_cmd,
-                                    choose_iftype_name(rule), &pid);
+               ret = exec_iptables_cmd(rule);
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for ingress"
                                 " traffic, for iftype %d, cmd %s, j %s",
                                 rule->iftype, set_cmd, jump_cmd);
 
+               //LCOV_EXCL_START
                /* for tethering */
                if (rule->intend == NFACCT_WARN ||
                    rule->intend == NFACCT_BLOCK) {
                        /* RULE_IFACE_OUT is not a misprint here */
-                       ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
-                                            FORWARD_RULE, nfacct_buf, jump_cmd,
-                                            choose_iftype_name(rule), &pid);
+                       nfacct_rule_direction temp_iotype = rule->iotype;
+
+                       rule->iotype = NFACCT_COUNTER_FORWARD;
+                       ret = exec_iptables_cmd(rule);
+                       rule->iotype = temp_iotype;
                        ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                         "Can't set forward rule for ingress "
                                         "traffic, for iftype %d, cmd %s, j %s",
@@ -800,7 +751,7 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                }
                /* tethering */
 
-               if (action == NFACCT_ACTION_DELETE) {
+               if (rule->action == NFACCT_ACTION_DELETE) {
                        rule->iptables_rule = nfacct_send_del;
                        set_finalize_flag(rule);
                        nfacct_send_get(rule);
@@ -808,15 +759,16 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                        ret_value_msg_if(ret != STC_ERROR_NONE, ret,
                                         "can't del quota counter");
                }
+               //LCOV_EXCL_STOP
        }
 
-       if (iotype & NFACCT_COUNTER_OUT) {
+       if (rule->iotype & NFACCT_COUNTER_OUT) {
                /* outcome part */
                rule->iotype = NFACCT_COUNTER_OUT;
-               rule->quota = send_limit;
+               rule->quota = rule->send_limit;
                generate_counter_name(rule);
 
-               if (action != NFACCT_ACTION_DELETE) {
+               if (rule->action != NFACCT_ACTION_DELETE) {
                        /* send delete comman in case of creation,
                         * because nfacct doesn't reset value for nfacct quota
                         * in case of quota existing */
@@ -835,19 +787,21 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
                                 STC_ERROR_FAIL, "Not enough buffer");
 
-               ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
-                                    nfacct_buf, jump_cmd,
-                                    choose_iftype_name(rule), &pid);
+               ret = exec_iptables_cmd(rule);
                ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                 "Can't set conditional block for "
                                 "engress traffic, for iftype %d, cmd %s, j %s",
                                 rule->iftype, set_cmd, jump_cmd);
+
+               //LCOV_EXCL_START
                /* for tethering  */
                if (rule->intend == NFACCT_WARN ||
                    rule->intend == NFACCT_BLOCK) {
-                       ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
-                                            FORWARD_RULE, nfacct_buf, jump_cmd,
-                                            choose_iftype_name(rule), &pid);
+                       nfacct_rule_direction temp_iotype = rule->iotype;
+
+                       rule->iotype = NFACCT_COUNTER_OUT;
+                       ret = exec_iptables_cmd(rule);
+                       rule->iotype = temp_iotype;
                        ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
                                         "Can't set forward rule for engress "
                                         "traffic, for iftype %d, cmd %s, j %s",
@@ -855,7 +809,7 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                }
                /* tethering  */
 
-               if (action == NFACCT_ACTION_DELETE) {
+               if (rule->action == NFACCT_ACTION_DELETE) {
                        rule->iptables_rule = nfacct_send_del;
                        set_finalize_flag(rule);
                        nfacct_send_get(rule);
@@ -863,34 +817,118 @@ static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
                        ret_value_msg_if(ret != STC_ERROR_NONE, ret,
                                         "can't del quota counter");
                }
+               //LCOV_EXCL_STOP
        }
+
        return STC_ERROR_NONE;
 }
 
-stc_error_e produce_net_rule(nfacct_rule_s *rule,
-                            const int64_t send_limit,
-                            const int64_t rcv_limit,
-                            const nfacct_rule_action action,
-                            const nfacct_rule_jump jump,
-                            const nfacct_rule_direction iotype)
+API stc_error_e produce_net_rule(nfacct_rule_s *rule)
 {
        stc_error_e ret = STC_ERROR_NONE;
 
-       if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN
-           && !send_limit && !rcv_limit)
+       if (rule == NULL)
+               return STC_ERROR_INVALID_PARAMETER;
+
+       if (rule->action == NFACCT_ACTION_APPEND &&
+           rule->intend == NFACCT_WARN &&
+           !rule->send_limit && !rule->rcv_limit)
                return STC_ERROR_NONE;
 
        if (rule->classid != STC_ALL_APP_CLASSID &&
            rule->classid != STC_TETHERING_APP_CLASSID &&
+           rule->classid != STC_BACKGROUND_APP_CLASSID &&
            rule->classid != STC_TOTAL_DATACALL_CLASSID &&
            rule->classid != STC_TOTAL_WIFI_CLASSID &&
-           rule->classid != STC_TOTAL_BLUETOOTH_CLASSID)
-               ret = produce_app_rule(rule, send_limit,
-                                      rcv_limit, action, jump, iotype);
+           rule->classid != STC_TOTAL_BLUETOOTH_CLASSID &&
+           rule->classid != STC_TOTAL_IPV4_CLASSID &&
+           rule->classid != STC_TOTAL_IPV6_CLASSID)
+               ret = produce_app_rule(rule);
        else
-               ret = produce_iface_rule(rule, send_limit, rcv_limit,
-                                        action, jump, iotype);
+               ret = produce_iface_rule(rule);
+
+       return ret;
+}
+
+static stc_error_e append_iptables_cmd(GSList **iptables_list, nfacct_rule_s *rule)
+{
+       iptables_rule_s *iptables_rule = NULL;
+
+       iptables_rule = MALLOC0(iptables_rule_s, 1);
+       if (!iptables_rule)
+               return STC_ERROR_OUT_OF_MEMORY;
+
+       iptables_rule->nfacct_name = g_strdup(rule->name);
+       iptables_rule->ifname = g_strdup(rule->ifname);
+       iptables_rule->target = g_strdup(get_iptables_jump(rule->jump));
+       iptables_rule->chain = g_strdup(get_iptables_chain(rule->classid,
+                               rule->iotype, rule->app_state, rule->intend));
+       if (rule->classid < STC_RESERVED_CLASSID_MAX)
+               iptables_rule->classid = STC_UNKNOWN_CLASSID;
+       else
+               iptables_rule->classid = rule->classid;
+       iptables_rule->direction = (rule->iotype & NFACCT_COUNTER_IN) ?
+                                       IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
+
+       *iptables_list = g_slist_append(*iptables_list, iptables_rule);
+
+       return STC_ERROR_NONE;
+}
+
+static void iptables_list_free(gpointer value)
+{
+       iptables_rule_s *iptables_rule = (iptables_rule_s *)value;
+
+       g_free(iptables_rule->chain);
+       g_free(iptables_rule->nfacct_name);
+       g_free(iptables_rule->ifname);
+       g_free(iptables_rule->target);
+       g_free(iptables_rule);
+}
+
+API stc_error_e produce_net_list(GSList *rule_list,
+               nfacct_rule_iptype iptype, nfacct_rule_action action)
+{
+       GSList *list = NULL;
+       GSList *iptables_list = NULL;
+       stc_error_e ret = STC_ERROR_NONE;
+
+       for (list = rule_list; list; list = list->next) {
+               nfacct_rule_s *rule = list->data;
+
+               if (rule->action == NFACCT_ACTION_APPEND &&
+                       rule->intend == NFACCT_WARN &&
+                       !rule->send_limit && !rule->rcv_limit)
+                       continue;
+
+               generate_counter_name(rule);
+               if (rule->action != NFACCT_ACTION_DELETE) {
+                       ret = nfacct_send_del(rule);
+                       if (ret != STC_ERROR_NONE)
+                               continue;
+
+                       ret = nfacct_send_new(rule);
+                       if (ret != STC_ERROR_NONE)
+                               continue;
+               }
+
+               append_iptables_cmd(&iptables_list, rule);
+       }
+
+       if (action == NFACCT_ACTION_INSERT ||
+               action == NFACCT_ACTION_APPEND)
+               ret = iptables_add_list(iptables_list, iptype);
+       else if (action == NFACCT_ACTION_DELETE)
+               ret = iptables_remove_list(iptables_list, iptype);
+
+       for (list = rule_list; list; list = list->next) {
+               nfacct_rule_s *rule = list->data;
+
+               if (rule->action == NFACCT_ACTION_DELETE)
+                       nfacct_send_del(rule);
+       }
 
+       g_slist_free_full(iptables_list, iptables_list_free);
        return ret;
 }
 
@@ -906,10 +944,17 @@ void generate_counter_name(nfacct_rule_s *counter)
                STRING_SAVE_COPY(counter->ifname, iftype_name);
        }
 
-       if (counter->intend  == NFACCT_WARN)
+       if (counter->intend  == NFACCT_WARN ||
+                       counter->intend == NFACCT_TETH_WARN)
                warn_symbol = 'w';
-       else if (counter->intend  == NFACCT_BLOCK)
+       else if (counter->intend  == NFACCT_BLOCK ||
+                       counter->intend == NFACCT_TETH_BLOCK)
                warn_symbol = 'r';
+       else if (counter->intend  == NFACCT_ALLOW ||
+                       counter->intend == NFACCT_TETH_ALLOW)
+               warn_symbol = 'a';
+       else if (counter->intend == NFACCT_TETH_COUNTER)
+               warn_symbol = 't';
        snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
                 warn_symbol, counter->iotype, counter->iftype,
                 counter->classid, counter->ifname);