X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fhelper%2Fhelper-nfacct-rule.c;h=ff703d37da9d086ee500fd58373013fe094c0df1;hb=refs%2Fheads%2Ftizen_5.5;hp=b46b3a41022cbedccc6ba1aa98e6f9b346ebdfbd;hpb=197057aab9d0dad19404fa2bbe59c544afdc2fe2;p=platform%2Fcore%2Fconnectivity%2Fstc-manager.git diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c index b46b3a4..ff703d3 100755 --- a/src/helper/helper-nfacct-rule.c +++ b/src/helper/helper-nfacct-rule.c @@ -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" @@ -47,13 +48,11 @@ #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);