#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
int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
(struct sockaddr *)&nladdr, sizeof(nladdr));
ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
- "Failed to send command to get outgoing traffic");
+ "Failed to send nfacct request, error [%d]", ret);
return STC_ERROR_NONE;
}
{
struct genl req;
+#if STC_DEBUG_LOG
STC_LOGD("send remove request for %s", counter->name);
+#endif
prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
add_string_attr(&req, counter->name, NFACCT_NAME);
iface = get_iftype_by_name(ifname_buf);
if (iface == STC_IFACE_DATACALL) {
cnt->iotype = NFACCT_COUNTER_OUT;
- strcpy(cnt->ifname, ifname_buf);
+ strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
}
}
{
int status;
pid_t ret_pid;
- char buf[BUF_SIZE_FOR_ERR] = { 0 };
- if (!pid) {
+ if (!pid || pid == -1) {
STC_LOGD("no need to wait");
return;
}
+
ret_pid = waitpid(pid, &status, 0);
- if (ret_pid < 0)
+ if (ret_pid < 0) {
+ char buf[BUF_SIZE_FOR_ERR] = { 0 };
STC_LOGD("can't wait for a pid %d %d %s", pid, status,
strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
+ }
}
static char* get_cmd_pos(const char *cmd_buf)
return cmd_pos;
}
-static bool is_rule_exists(const char *cmd_buf)
+static bool is_rule_present(const char *cmd_buf)
{
- size_t buf_len;
- char *exec_buf;
- char *cmd_pos = get_cmd_pos(cmd_buf);
bool ret = false;
- if (!cmd_pos)
- return false;
+ pid_t pid = fork();
- buf_len = strlen(cmd_buf) + 1;
- exec_buf = (char *)malloc(buf_len);
- if (!exec_buf)
- return false;
+ if (pid == 0) {
+ gchar **args = NULL;
+ size_t buf_len;
+ char *exec_buf;
+ char *cmd_pos = get_cmd_pos(cmd_buf);
+
+ if (!cmd_pos)
+ exit(1);
- strncpy(exec_buf, cmd_buf, buf_len);
- strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
- sizeof(IPTABLES_CHECK) - 1);
+ buf_len = strlen(cmd_buf) + 1;
+ exec_buf = (char *)malloc(buf_len);
+ if (!exec_buf)
+ exit(1);
- STC_LOGD("check rule %s", exec_buf);
+ strncpy(exec_buf, cmd_buf, buf_len);
+ strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
+ sizeof(IPTABLES_CHECK) - 1);
+
+#if STC_DEBUG_LOG
+ STC_LOGD("check rule %s", exec_buf);
+#endif
+
+ args = g_strsplit_set(exec_buf, " ", -1);
+
+ ret = execv(args[0], args);
+ if (ret) {
+ char buf[BUF_SIZE_FOR_ERR] = { 0 };
+ STC_LOGE("Can't execute %s: %s",
+ cmd_buf, strerror_r(errno, buf,
+ BUF_SIZE_FOR_ERR));
+ }
+
+ free(exec_buf);
+ g_strfreev(args);
+ exit(ret);
+ }
- ret = system(exec_buf) == 0;
- free(exec_buf);
return ret;
}
stc_error_e exec_iptables_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;
- const size_t args_number = get_args_number(cmd_buf);
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);
- ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
+#if STC_DEBUG_LOG
+ STC_LOGD("executing iptables cmd %s in forked process", cmd_buf);
+#endif
- if (is_rule_exists(cmd_buf)) {
- STC_LOGD("Rule %s already exists", cmd_buf);
+ if (is_rule_present(cmd_buf)) {
+ STC_LOGD("Rule %s already present", cmd_buf);
exit(0);
}
+
args[0] = "iptables";
cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
- ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments");
+ if (cmd == NULL) {
+ STC_LOGE("no arguments");
+ exit(-EINVAL);
+ }
+
for (i = 1; i <= args_number; ++i)
args[i] = strtok_r(NULL, " ", &save_ptr);
args[i] = NULL;
ret = execv(cmd, args);
- if (ret)
+ if (ret) {
+ char buf[BUF_SIZE_FOR_ERR] = { 0 };
STC_LOGE("Can't execute %s: %s",
- cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
+ cmd_buf, strerror_r(errno, buf,
+ BUF_SIZE_FOR_ERR));
+ }
exit(ret);
}
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;
- const size_t args_number = get_args_number(cmd_buf);
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);
- ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
+#if STC_DEBUG_LOG
+ STC_LOGD("executing ip6tables cmd %s in forked process", cmd_buf);
+#endif
- if (is_rule_exists(cmd_buf)) {
- STC_LOGD("Rule %s already exists", cmd_buf);
+ if (is_rule_present(cmd_buf)) {
+ STC_LOGD("Rule %s already present", cmd_buf);
exit(0);
}
+
args[0] = "ip6tables";
cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
- ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments");
+ if (cmd == NULL) {
+ STC_LOGE("no arguments");
+ exit(-EINVAL);
+ }
+
for (i = 1; i <= args_number; ++i)
args[i] = strtok_r(NULL, " ", &save_ptr);
args[i] = NULL;
ret = execv(cmd, args);
- if (ret)
+ if (ret) {
+ char buf[BUF_SIZE_FOR_ERR] = { 0 };
STC_LOGE("Can't execute %s: %s",
- cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
+ cmd_buf, strerror_r(errno, buf,
+ BUF_SIZE_FOR_ERR));
+ }
exit(ret);
}
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)
+ pid_t *pid, nfacct_rule_iptype iptype)
{
char block_buf[MAX_PATH_LENGTH];
int ret;
+ const char *iptables_type = IPTABLES;
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);
+ if (iptype == NFACCT_TYPE_IPV6)
+ iptables_type = IP6TABLES;
- /* ip6tables rule */
- ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd, chain,
- iftype_name, nfacct, jump);
+ ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
+ cmd, chain, iftype_name, nfacct, jump);
ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
"Not enough buffer");
- return exec_ip6tables_cmd(block_buf, pid);
+
+ if (iptype == NFACCT_TYPE_IPV6)
+ exec_ip6tables_cmd(block_buf, pid);
+ else
+ exec_iptables_cmd(block_buf, pid);
+
+ wait_for_rule_cmd(*pid);
+
+ return STC_ERROR_NONE;
}
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)
+ pid_t *pid, nfacct_rule_iptype iptype)
{
char block_buf[MAX_PATH_LENGTH];
int ret;
+ const char *iptables_type = IPTABLES;
+
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);
+ if (iptype == NFACCT_TYPE_IPV6)
+ iptables_type = IP6TABLES;
- /* ip6tables rules */
- ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd,
- iftype_name, classid, nfacct, jump);
+ ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
+ cmd, iftype_name, classid, nfacct, jump);
ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
"Not enough buffer");
- return exec_ip6tables_cmd(block_buf, pid);
+
+ if (iptype == NFACCT_TYPE_IPV6)
+ exec_ip6tables_cmd(block_buf, pid);
+ else
+ exec_iptables_cmd(block_buf, pid);
+
+ wait_for_rule_cmd(*pid);
+
+ return STC_ERROR_NONE;
}
static char *get_iptables_cmd(const nfacct_rule_action action)
return "";
}
-static stc_error_e produce_app_rule(nfacct_rule_s *rule,
- const uint64_t send_limit,
- const uint64_t rcv_limit,
- const nfacct_rule_action action,
- const nfacct_rule_jump jump,
- const nfacct_rule_direction iotype)
+static stc_error_e produce_app_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];
stc_error_e ret = STC_ERROR_NONE;
pid_t pid = 0;
/* 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");
ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
rule->classid, choose_iftype_name(rule),
- &pid);
+ &pid, rule->iptype);
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,
* due it's not clear when actual counters was stored,
* and based on which value settings made such decition */
- wait_for_rule_cmd(pid);
rule->iptables_rule = nfacct_send_del;
set_finalize_flag(rule);
nfacct_send_get(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");
ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
rule->classid, choose_iftype_name(rule),
- &pid);
+ &pid, rule->iptype);
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) {
- wait_for_rule_cmd(pid);
+ 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,
return STC_ERROR_NONE;
}
-static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
- const uint64_t send_limit,
- const uint64_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];
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 */
ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
get_iptables_chain(rule->iotype),
nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid);
+ choose_iftype_name(rule), &pid,
+ rule->iptype);
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",
if (rule->intend == NFACCT_WARN ||
rule->intend == NFACCT_BLOCK) {
/* RULE_IFACE_OUT is not a misprint here */
- wait_for_rule_cmd(pid);
ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
FORWARD_RULE, nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid);
+ choose_iftype_name(rule), &pid,
+ rule->iptype);
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",
}
/* tethering */
- if (action == NFACCT_ACTION_DELETE) {
- wait_for_rule_cmd(pid);
+ if (rule->action == NFACCT_ACTION_DELETE) {
rule->iptables_rule = nfacct_send_del;
set_finalize_flag(rule);
nfacct_send_get(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) {
/* send delete comman in case of creation,
* because nfacct doesn't reset value for nfacct quota
* in case of quota existing */
ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
STC_ERROR_FAIL, "Not enough buffer");
- wait_for_rule_cmd(pid);
ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid);
+ choose_iftype_name(rule), &pid,
+ rule->iptype);
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",
/* for tethering */
if (rule->intend == NFACCT_WARN ||
rule->intend == NFACCT_BLOCK) {
- wait_for_rule_cmd(pid);
ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
FORWARD_RULE, nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid);
+ choose_iftype_name(rule), &pid,
+ rule->iptype);
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",
}
/* tethering */
- if (action == NFACCT_ACTION_DELETE) {
- wait_for_rule_cmd(pid);
+ if (rule->action == NFACCT_ACTION_DELETE) {
rule->iptables_rule = nfacct_send_del;
set_finalize_flag(rule);
nfacct_send_get(rule);
return STC_ERROR_NONE;
}
-stc_error_e produce_net_rule(nfacct_rule_s *rule,
- const uint64_t send_limit,
- const uint64_t rcv_limit,
- const nfacct_rule_action action,
- const nfacct_rule_jump jump,
- const nfacct_rule_direction iotype)
+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)
- ret = produce_app_rule(rule, send_limit,
- rcv_limit, action, jump, iotype);
+ rule->classid != STC_TETHERING_APP_CLASSID &&
+ rule->classid != STC_TOTAL_DATACALL_CLASSID &&
+ rule->classid != STC_TOTAL_WIFI_CLASSID &&
+ 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;
}