2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <sys/types.h>
25 #include <arpa/inet.h>
28 #include "helper-nfacct-rule.h"
30 #include "configure_stub.h"
32 #define IPTABLES "/usr/sbin/iptables"
33 #define IP6TABLES "/usr/sbin/ip6tables"
34 #define IPTABLES_CHECK "-C"
39 #define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
40 #define REJECT_RULE " -j REJECT"
41 #define ACCEPT_RULE " -j ACCEPT"
42 #define OUT_RULE "OUTPUT"
43 #define IN_RULE "INPUT"
44 #define FORWARD_RULE "FORWARD"
46 /* TODO idea to use the same rule both for BLOCK (REJECT) and WARNING (ACCEPT) */
47 #define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s"
48 #define RULE_APP_IN "%s -w %s INPUT -i %s -m cgroup --cgroup %u %s %s"
51 /* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
53 #define RULE_IFACE_OUT "%s -w %s %s -o %s %s %s"
54 #define RULE_IFACE_IN "%s -w %s %s -i %s %s %s"
57 #define NFNL_SUBSYS_ACCT 7
58 #define BUF_SIZE_FOR_ERR 100
60 static void prepare_netlink_msg(struct genl *req, int type, int flag)
63 memset(req, 0, sizeof(struct genl));
64 req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
65 req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type;
66 req->n.nlmsg_flags = NLM_F_REQUEST | flag;
67 req->n.nlmsg_seq = seq;
70 static void add_value_attr(struct genl *req, const void *data, int len,
75 struct nlattr *na = (struct nlattr *)((char *)req +
76 NLMSG_ALIGN(req->n.nlmsg_len));
79 payload = len + NLA_HDRLEN;
80 na->nla_len = payload;
81 memcpy(NLA_DATA(na), data, len);
82 req->n.nlmsg_len += NLMSG_ALIGN(payload);
86 * following 2 function should be used in combination.
87 * start_nest_attr returns nlattr structure, which should be completed by
89 * before these invocations any number of netlink arguments could be inserted
91 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
93 struct nlattr *start = (struct nlattr *)((char *)req +
94 NLMSG_ALIGN(req->n.nlmsg_len));
96 start->nla_type = NLA_F_NESTED | type;
97 req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
101 static void end_nest_attr(struct genl *req, struct nlattr *start)
103 start->nla_len = (__u16)((char *)req +
104 NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
107 static void add_string_attr(struct genl *req, const char *str, int type)
109 add_value_attr(req, str, strlen(str) + 1, type);
112 static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
114 add_value_attr(req, &v, sizeof(v), type);
117 /* macros or templare, due uint64 and uint32 is the same functions */
118 static void add_uint32_attr(struct genl *req, const uint32_t v, int type)
120 add_value_attr(req, &v, sizeof(v), type);
123 static stc_error_e send_nfacct_request(int sock, struct genl *req)
125 struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
126 int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
127 (struct sockaddr *)&nladdr, sizeof(nladdr));
128 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
129 "Failed to send nfacct request, error [%d]", ret);
131 return STC_ERROR_NONE;
134 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
138 prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
139 add_string_attr(&req, counter->name, NFACCT_NAME);
141 STC_LOGD("counter name %s", counter->name);
144 add_uint64_attr(&req, 0, NFACCT_PKTS);
145 add_uint64_attr(&req, 0, NFACCT_BYTES);
146 if (counter->quota) {
147 STC_LOGD("quota bytes %"PRId64, counter->quota);
149 add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES),
151 add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA);
154 return send_nfacct_request(counter->carg->sock, &req);
157 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
161 STC_LOGD("send remove request for %s", counter->name);
163 prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
164 add_string_attr(&req, counter->name, NFACCT_NAME);
165 return send_nfacct_request(counter->carg->sock, &req);
167 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
169 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
170 enum nfnl_acct_msg_types get_type,
172 int mask, int filter)
176 int flag = !name ? NLM_F_DUMP : 0;
177 prepare_netlink_msg(&req, get_type,
179 /* due we don't get counter with quota any where else,
180 * here we will request just counters by default */
182 add_string_attr(&req, name, NFACCT_NAME);
184 na = start_nest_attr(&req, NFACCT_FILTER);
185 add_uint32_attr(&req, htonl(mask),
186 NFACCT_FILTER_ATTR_MASK);
187 add_uint32_attr(&req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
188 end_nest_attr(&req, na);
189 return send_nfacct_request(carg->sock, &req);
192 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
194 /* get and reset countes value */
195 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
199 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
201 /* just get counters */
202 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name,
203 NFACCT_F_QUOTA_BYTES,
204 NFACCT_F_QUOTA_BYTES);
207 stc_error_e nfacct_send_get_all(struct counter_arg *carg)
209 /* get and reset everything, used when quiting */
210 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
214 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
216 if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
217 return nfacct_send_get_quotas(rule->carg, rule->name);
218 else if (rule->intend == NFACCT_COUNTER)
219 return nfacct_send_get_counters(rule->carg, rule->name);
221 return STC_ERROR_INVALID_PARAMETER;
224 static nfacct_rule_direction convert_to_iotype(int type)
226 return (type < NFACCT_COUNTER_LAST_ELEM &&
227 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
230 static stc_iface_type_e convert_to_iftype(int type)
232 return (type < STC_IFACE_LAST_ELEM &&
233 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
236 bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
242 char *save_ptr = NULL;
243 char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
245 strncpy(name, cnt_name, sizeof(name) - 1);
249 cnt->intend = NFACCT_COUNTER;
252 cnt->intend = NFACCT_WARN;
255 cnt->intend = NFACCT_BLOCK;
258 cnt->intend = NFACCT_TETH_COUNTER;
264 STRING_SAVE_COPY(cnt->name, cnt_name);
266 if (cnt->intend == NFACCT_TETH_COUNTER) {
267 char ifname_buf[MAX_IFACE_LENGTH];
269 stc_iface_type_e iface;
270 /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
271 * it's outgoing traffic, due all tethering is mobile databased */
272 iftype_part = strchr(name, ':');
273 ret_value_msg_if(iftype_part == NULL,
274 false, "Invalid format of the tethering counter %s", name);
275 ifname_len = iftype_part - name - 1;
276 strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
277 ifname_buf[ifname_len] = '\0';
278 iface = get_iftype_by_name(ifname_buf);
279 /* check first part is it datacall */
280 if (iface == STC_IFACE_DATACALL) {
281 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
282 cnt->iotype = NFACCT_COUNTER_IN;
284 /* +1, due : symbol and till the end of cnt_name */
285 strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH);
286 iface = get_iftype_by_name(ifname_buf);
287 if (iface == STC_IFACE_DATACALL) {
288 cnt->iotype = NFACCT_COUNTER_OUT;
289 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
293 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
294 STC_LOGE("can't determine tethering direction %s", name);
297 cnt->iftype = STC_IFACE_DATACALL;
298 cnt->classid = STC_TETHERING_APP_CLASSID;
302 io_part = strtok_r(name, "_", &save_ptr);
304 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
308 iftype_part = strtok_r(NULL, "_", &save_ptr);
309 if (iftype_part != NULL)
310 cnt->iftype = convert_to_iftype(atoi(iftype_part));
314 classid_part = strtok_r(NULL, "_", &save_ptr);
315 if (classid_part != NULL)
316 cnt->classid = atoi(classid_part);
318 cnt->classid = STC_ALL_APP_CLASSID;
319 return cnt->intend == NFACCT_BLOCK ? true : false;
322 ifname_part = strtok_r(NULL, "\0", &save_ptr);
323 if (ifname_part != NULL)
324 STRING_SAVE_COPY(cnt->ifname, ifname_part);
331 static void _process_answer(struct netlink_serialization_params *params)
334 struct rtattr *attr_list[__NFACCT_MAX] = {0};
335 struct counter_arg *carg = params->carg;
336 struct genl *ans = params->ans;;
337 struct nlmsghdr *nlhdr = &ans->n;
338 int len = GENLMSG_PAYLOAD(nlhdr);
339 int ans_len = carg->ans_len;
344 /* parse reply message */
345 na = (struct rtattr *)GENLMSG_DATA(ans);
347 while (NLMSG_OK(nlhdr, ans_len)) {
348 fill_attribute_list(attr_list, NFACCT_MAX,
350 if (!attr_list[NFACCT_NAME] ||
351 !attr_list[NFACCT_BYTES])
353 params->eval_attr(attr_list, carg);
356 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
359 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
362 if (params->post_eval_attr)
363 params->post_eval_attr(carg);
366 netlink_serialization_command *
367 netlink_create_command(struct netlink_serialization_params *params)
369 static netlink_serialization_command command = {0,};
370 command.deserialize_answer = _process_answer;
371 command.params = *params;
375 static unsigned int get_args_number(const char *cmd_buf)
378 unsigned int count = 0;
380 for (str = (char *)cmd_buf; *str != '\0'; ++str) {
387 static void wait_for_rule_cmd(pid_t pid)
391 char buf[BUF_SIZE_FOR_ERR] = { 0 };
394 STC_LOGD("no need to wait");
397 ret_pid = waitpid(pid, &status, 0);
399 STC_LOGD("can't wait for a pid %d %d %s", pid, status,
400 strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
403 static char* get_cmd_pos(const char *cmd_buf)
405 char *cmd_pos = strstr(cmd_buf, APPEND);
407 cmd_pos = strstr(cmd_buf, INSERT);
412 static bool is_rule_exists(const char *cmd_buf)
416 char *cmd_pos = get_cmd_pos(cmd_buf);
421 buf_len = strlen(cmd_buf) + 1;
422 exec_buf = (char *)malloc(buf_len);
426 strncpy(exec_buf, cmd_buf, buf_len);
427 strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
428 sizeof(IPTABLES_CHECK) - 1);
430 STC_LOGD("check rule %s", exec_buf);
432 ret = system(exec_buf) == 0;
437 stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
444 const size_t args_number = get_args_number(cmd_buf);
445 char *args[args_number + 2];
447 char *save_ptr = NULL;
448 char buf[BUF_SIZE_FOR_ERR] = { 0 };
450 STC_LOGD("executing iptables cmd %s in forked process",
453 ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
455 if (is_rule_exists(cmd_buf)) {
456 STC_LOGD("Rule %s already exists", cmd_buf);
459 args[0] = "iptables";
460 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
461 ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments");
462 for (i = 1; i <= args_number; ++i)
463 args[i] = strtok_r(NULL, " ", &save_ptr);
467 ret = execv(cmd, args);
469 STC_LOGE("Can't execute %s: %s",
470 cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
475 return STC_ERROR_NONE;
478 stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
485 const size_t args_number = get_args_number(cmd_buf);
486 char *args[args_number + 2];
488 char *save_ptr = NULL;
489 char buf[BUF_SIZE_FOR_ERR] = { 0 };
491 STC_LOGD("executing ip6tables cmd %s in forked process",
494 ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
496 if (is_rule_exists(cmd_buf)) {
497 STC_LOGD("Rule %s already exists", cmd_buf);
500 args[0] = "ip6tables";
501 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
502 ret_value_msg_if(cmd == NULL, STC_ERROR_FAIL, "no arguments");
503 for (i = 1; i <= args_number; ++i)
504 args[i] = strtok_r(NULL, " ", &save_ptr);
508 ret = execv(cmd, args);
510 STC_LOGE("Can't execute %s: %s",
511 cmd_buf, strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
516 return STC_ERROR_NONE;
519 static char *choose_iftype_name(nfacct_rule_s *rule)
521 return strlen(rule->ifname) != 0 ? rule->ifname :
522 get_iftype_name(rule->iftype);
525 static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd,
526 const char *chain, const char *nfacct,
527 const char *jump, char *iftype_name,
530 char block_buf[MAX_PATH_LENGTH];
533 ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
534 "Invalid network interface name argument");
537 ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd, chain,
538 iftype_name, nfacct, jump);
539 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
540 "Not enough buffer");
541 exec_iptables_cmd(block_buf, pid);
544 ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd, chain,
545 iftype_name, nfacct, jump);
546 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
547 "Not enough buffer");
548 return exec_ip6tables_cmd(block_buf, pid);
551 static stc_error_e exec_app_cmd(const char *pattern, const char *cmd,
552 const char *nfacct, const char *jump,
553 const uint32_t classid, char *iftype_name,
556 char block_buf[MAX_PATH_LENGTH];
558 ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
559 "Invalid network interface name argument");
562 ret = snprintf(block_buf, sizeof(block_buf), pattern, IPTABLES, cmd,
563 iftype_name, classid, nfacct, jump);
564 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
565 "Not enough buffer");
566 exec_iptables_cmd(block_buf, pid);
568 /* ip6tables rules */
569 ret = snprintf(block_buf, sizeof(block_buf), pattern, IP6TABLES, cmd,
570 iftype_name, classid, nfacct, jump);
571 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
572 "Not enough buffer");
573 return exec_ip6tables_cmd(block_buf, pid);
576 static char *get_iptables_cmd(const nfacct_rule_action action)
578 if (action == NFACCT_ACTION_APPEND)
580 else if (action == NFACCT_ACTION_DELETE)
582 else if (action == NFACCT_ACTION_INSERT)
588 static char *get_iptables_chain(const nfacct_rule_direction iotype)
590 if (iotype == NFACCT_COUNTER_IN)
592 else if (iotype == NFACCT_COUNTER_OUT)
598 static char *get_iptables_jump(const nfacct_rule_jump jump)
600 if (jump == NFACCT_JUMP_ACCEPT)
602 else if (jump == NFACCT_JUMP_REJECT)
608 static stc_error_e produce_app_rule(nfacct_rule_s *rule,
609 const int64_t send_limit,
610 const int64_t rcv_limit,
611 const nfacct_rule_action action,
612 const nfacct_rule_jump jump,
613 const nfacct_rule_direction iotype)
615 char *set_cmd = get_iptables_cmd(action);
616 char *jump_cmd = get_iptables_jump(jump);
617 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
618 3*MAX_DEC_SIZE(int) + 4];
619 stc_error_e ret = STC_ERROR_NONE;
623 if (iotype & NFACCT_COUNTER_IN) {
624 rule->quota = rcv_limit;
625 rule->iotype = NFACCT_COUNTER_IN;
626 generate_counter_name(rule);
628 /* to support quated counter we need nfacct,
629 * don't use it in case of just block without a limit
630 * iow, send_limit = 0 and rcv_limit 0 */
631 if (action != NFACCT_ACTION_DELETE) {
632 ret = nfacct_send_del(rule);
633 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
634 "can't del quota counter");
636 ret = nfacct_send_new(rule);
637 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
638 "can't set nfacct counter");
642 /* we have a counter, let's key in a rule, drop in case of
643 * send_limit/rcv_limit */
644 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
646 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
647 STC_ERROR_FAIL, "Not enought buffer");
649 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
650 rule->classid, choose_iftype_name(rule),
652 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
653 "Can't set conditional block for ingress"
654 " traffic, for classid %u, cmd %s, j %s",
655 rule->classid, set_cmd, jump_cmd);
657 /* remove in any case */
658 if (action == NFACCT_ACTION_DELETE) {
659 /* TODO here and everywhere should be not just a del,
660 * here should be get counted value and than
661 * set new counter with that value, but it's minor issue,
662 * due it's not clear when actual counters was stored,
663 * and based on which value settings made such decition */
664 wait_for_rule_cmd(pid);
665 rule->iptables_rule = nfacct_send_del;
666 set_finalize_flag(rule);
667 nfacct_send_get(rule);
668 ret = nfacct_send_del(rule);
669 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
670 "can't del quota counter");
674 if (iotype & NFACCT_COUNTER_OUT) {
676 rule->iotype = NFACCT_COUNTER_OUT;
677 rule->quota = send_limit;
678 generate_counter_name(rule);
679 if (action != NFACCT_ACTION_DELETE) {
680 ret = nfacct_send_del(rule);
681 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
682 "can't del quota counter");
684 ret = nfacct_send_new(rule);
685 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
686 "can't set quota counter");
690 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
692 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
693 STC_ERROR_FAIL, "Not enought buffer");
695 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
696 rule->classid, choose_iftype_name(rule),
698 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
699 "Can't set conditional block for engress"
700 " traffic, for classid %u, cmd %s, j %s",
701 rule->classid, set_cmd, jump_cmd);
702 if (action == NFACCT_ACTION_DELETE) {
703 wait_for_rule_cmd(pid);
704 rule->iptables_rule = nfacct_send_del;
705 /* not effective, it's better to replace
706 * set_finalize_flag by set_property,
707 * due keep_counter it necessary only for
708 * setting iptables_rule */
709 set_finalize_flag(rule);
710 nfacct_send_get(rule);
711 ret = nfacct_send_del(rule);
712 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
713 "can't del quota counter");
716 return STC_ERROR_NONE;
719 static stc_error_e produce_iface_rule(nfacct_rule_s *rule,
720 const int64_t send_limit,
721 const int64_t rcv_limit,
722 const nfacct_rule_action action,
723 const nfacct_rule_jump jump,
724 const nfacct_rule_direction iotype)
726 char *set_cmd = get_iptables_cmd(action);
727 char *jump_cmd = get_iptables_jump(jump);
728 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
729 3*MAX_DEC_SIZE(int) + 4];
733 if (iotype & NFACCT_COUNTER_IN) {
735 rule->iotype = NFACCT_COUNTER_IN;
736 rule->quota = rcv_limit;
737 generate_counter_name(rule);
739 if (action != NFACCT_ACTION_DELETE) {
740 /* send delete comman in case of creation,
741 * because nfacct doesn't reset value for nfacct quota
742 * in case of quota existing */
743 ret = nfacct_send_del(rule);
744 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
745 "can't del quota counter");
747 ret = nfacct_send_new(rule);
748 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
749 "can't set quota counter");
753 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
754 NFACCT_NAME_MOD, rule->name);
755 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
756 STC_ERROR_FAIL, "Not enought buffer");
758 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
759 get_iptables_chain(rule->iotype),
760 nfacct_buf, jump_cmd,
761 choose_iftype_name(rule), &pid);
762 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
763 "Can't set conditional block for ingress"
764 " traffic, for iftype %d, cmd %s, j %s",
765 rule->iftype, set_cmd, jump_cmd);
768 if (rule->intend == NFACCT_WARN ||
769 rule->intend == NFACCT_BLOCK) {
770 /* RULE_IFACE_OUT is not a misprint here */
771 wait_for_rule_cmd(pid);
772 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
773 FORWARD_RULE, nfacct_buf, jump_cmd,
774 choose_iftype_name(rule), &pid);
775 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
776 "Can't set forward rule for ingress "
777 "traffic, for iftype %d, cmd %s, j %s",
778 rule->iftype, set_cmd, jump_cmd);
782 if (action == NFACCT_ACTION_DELETE) {
783 wait_for_rule_cmd(pid);
784 rule->iptables_rule = nfacct_send_del;
785 set_finalize_flag(rule);
786 nfacct_send_get(rule);
787 ret = nfacct_send_del(rule);
788 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
789 "can't del quota counter");
793 if (iotype & NFACCT_COUNTER_OUT) {
795 rule->iotype = NFACCT_COUNTER_OUT;
796 rule->quota = send_limit;
797 generate_counter_name(rule);
799 if (action != NFACCT_ACTION_DELETE) {
800 /* send delete comman in case of creation,
801 * because nfacct doesn't reset value for nfacct quota
802 * in case of quota existing */
803 ret = nfacct_send_del(rule);
804 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
805 "can't del quota counter");
807 ret = nfacct_send_new(rule);
808 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
809 "can't set quota counter");
813 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
814 NFACCT_NAME_MOD, rule->name);
815 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
816 STC_ERROR_FAIL, "Not enough buffer");
818 wait_for_rule_cmd(pid);
819 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
820 nfacct_buf, jump_cmd,
821 choose_iftype_name(rule), &pid);
822 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
823 "Can't set conditional block for "
824 "engress traffic, for iftype %d, cmd %s, j %s",
825 rule->iftype, set_cmd, jump_cmd);
827 if (rule->intend == NFACCT_WARN ||
828 rule->intend == NFACCT_BLOCK) {
829 wait_for_rule_cmd(pid);
830 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
831 FORWARD_RULE, nfacct_buf, jump_cmd,
832 choose_iftype_name(rule), &pid);
833 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
834 "Can't set forward rule for engress "
835 "traffic, for iftype %d, cmd %s, j %s",
836 rule->iftype, set_cmd, jump_cmd);
840 if (action == NFACCT_ACTION_DELETE) {
841 wait_for_rule_cmd(pid);
842 rule->iptables_rule = nfacct_send_del;
843 set_finalize_flag(rule);
844 nfacct_send_get(rule);
845 ret = nfacct_send_del(rule);
846 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
847 "can't del quota counter");
850 return STC_ERROR_NONE;
853 stc_error_e produce_net_rule(nfacct_rule_s *rule,
854 const int64_t send_limit,
855 const int64_t rcv_limit,
856 const nfacct_rule_action action,
857 const nfacct_rule_jump jump,
858 const nfacct_rule_direction iotype)
860 stc_error_e ret = STC_ERROR_NONE;
862 if (action == NFACCT_ACTION_APPEND && rule->intend == NFACCT_WARN
863 && !send_limit && !rcv_limit)
864 return STC_ERROR_NONE;
866 if (rule->classid != STC_ALL_APP_CLASSID &&
867 rule->classid != STC_TETHERING_APP_CLASSID &&
868 rule->classid != STC_TOTAL_DATACALL_CLASSID &&
869 rule->classid != STC_TOTAL_WIFI_CLASSID &&
870 rule->classid != STC_TOTAL_BLUETOOTH_CLASSID)
871 ret = produce_app_rule(rule, send_limit,
872 rcv_limit, action, jump, iotype);
874 ret = produce_iface_rule(rule, send_limit, rcv_limit,
875 action, jump, iotype);
880 void generate_counter_name(nfacct_rule_s *counter)
882 char warn_symbol = 'c';
883 if (!strlen(counter->ifname)) {
884 char *iftype_name = get_iftype_name(counter->iftype);
885 /* trace counter name, maybe name was already generated */
886 ret_msg_if(iftype_name == NULL,
887 "Can't get interface name for counter %s, iftype %d)!",
888 counter->name, counter->iftype);
889 STRING_SAVE_COPY(counter->ifname, iftype_name);
892 if (counter->intend == NFACCT_WARN)
894 else if (counter->intend == NFACCT_BLOCK)
896 snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
897 warn_symbol, counter->iotype, counter->iftype,
898 counter->classid, counter->ifname);