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"
50 /* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
52 #define RULE_IFACE_OUT "%s -w %s %s -o %s %s %s"
53 #define RULE_IFACE_IN "%s -w %s %s -i %s %s %s"
55 #define NFNL_SUBSYS_ACCT 7
56 #define BUF_SIZE_FOR_ERR 100
58 static void prepare_netlink_msg(struct genl *req, int type, int flag)
61 memset(req, 0, sizeof(struct genl));
62 req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
63 req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type;
64 req->n.nlmsg_flags = NLM_F_REQUEST | flag;
65 req->n.nlmsg_seq = seq;
68 static void add_value_attr(struct genl *req, const void *data, int len,
73 struct nlattr *na = (struct nlattr *)((char *)req +
74 NLMSG_ALIGN(req->n.nlmsg_len));
77 payload = len + NLA_HDRLEN;
78 na->nla_len = payload;
79 memcpy(NLA_DATA(na), data, len);
80 req->n.nlmsg_len += NLMSG_ALIGN(payload);
84 * following 2 function should be used in combination.
85 * start_nest_attr returns nlattr structure, which should be completed by
87 * before these invocations any number of netlink arguments could be inserted
89 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
91 struct nlattr *start = (struct nlattr *)((char *)req +
92 NLMSG_ALIGN(req->n.nlmsg_len));
94 start->nla_type = NLA_F_NESTED | type;
95 req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
99 static void end_nest_attr(struct genl *req, struct nlattr *start)
101 start->nla_len = (__u16)((char *)req +
102 NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
105 static void add_string_attr(struct genl *req, const char *str, int type)
107 add_value_attr(req, str, strlen(str) + 1, type);
110 static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
112 add_value_attr(req, &v, sizeof(v), type);
115 /* macros or templare, due uint64 and uint32 is the same functions */
116 static void add_uint32_attr(struct genl *req, const uint32_t v, int type)
118 add_value_attr(req, &v, sizeof(v), type);
121 static stc_error_e send_nfacct_request(int sock, struct genl *req)
123 struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
124 int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
125 (struct sockaddr *)&nladdr, sizeof(nladdr));
126 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
127 "Failed to send nfacct request, error [%d]", ret);
129 return STC_ERROR_NONE;
132 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
134 int ret = STC_ERROR_NONE;
135 struct genl *req = MALLOC0(struct genl, 1);
137 STC_LOGE("Failed allocate memory to genl request message");
138 return STC_ERROR_OUT_OF_MEMORY;
141 prepare_netlink_msg(req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
142 add_string_attr(req, counter->name, NFACCT_NAME);
145 STC_LOGD("counter name %s", counter->name);
148 add_uint64_attr(req, 0, NFACCT_PKTS);
149 add_uint64_attr(req, 0, NFACCT_BYTES);
150 if (counter->quota) {
151 STC_LOGD("quota bytes %"PRId64, counter->quota);
153 add_uint32_attr(req, htobe32(NFACCT_F_QUOTA_BYTES),
155 add_uint64_attr(req, htobe64(counter->quota), NFACCT_QUOTA);
158 ret = send_nfacct_request(counter->carg->sock, req);
163 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
165 int ret = STC_ERROR_NONE;
166 struct genl *req = MALLOC0(struct genl, 1);
168 STC_LOGE("Failed allocate memory to genl request message");
169 return STC_ERROR_OUT_OF_MEMORY;
173 STC_LOGD("send remove request for %s", counter->name);
175 prepare_netlink_msg(req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
176 add_string_attr(req, counter->name, NFACCT_NAME);
178 ret = send_nfacct_request(counter->carg->sock, req);
182 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
184 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
185 enum nfnl_acct_msg_types get_type,
187 int mask, int filter)
189 int ret = STC_ERROR_NONE;
191 int flag = !name ? NLM_F_DUMP : 0;
192 struct genl *req = MALLOC0(struct genl, 1);
194 STC_LOGE("Failed allocate memory to genl request message");
195 return STC_ERROR_OUT_OF_MEMORY;
198 prepare_netlink_msg(req, get_type, flag);
199 /* due we don't get counter with quota any where else,
200 * here we will request just counters by default */
202 add_string_attr(req, name, NFACCT_NAME);
204 na = start_nest_attr(req, NFACCT_FILTER);
205 add_uint32_attr(req, htonl(mask), NFACCT_FILTER_ATTR_MASK);
206 add_uint32_attr(req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
207 end_nest_attr(req, na);
209 ret = send_nfacct_request(carg->sock, req);
214 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
216 /* get and reset countes value */
217 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
221 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
223 /* just get counters */
224 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name,
225 NFACCT_F_QUOTA_BYTES,
226 NFACCT_F_QUOTA_BYTES);
229 stc_error_e nfacct_send_get_all(struct counter_arg *carg)
231 /* get and reset everything, used when quiting */
232 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
236 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
238 if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
239 return nfacct_send_get_quotas(rule->carg, rule->name);
240 else if (rule->intend == NFACCT_COUNTER)
241 return nfacct_send_get_counters(rule->carg, rule->name);
243 return STC_ERROR_INVALID_PARAMETER;
246 static nfacct_rule_direction convert_to_iotype(int type)
248 return (type < NFACCT_COUNTER_LAST_ELEM &&
249 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
252 static stc_iface_type_e convert_to_iftype(int type)
254 return (type < STC_IFACE_LAST_ELEM &&
255 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
258 bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
264 char *save_ptr = NULL;
265 char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
267 strncpy(name, cnt_name, sizeof(name) - 1);
271 cnt->intend = NFACCT_COUNTER;
274 cnt->intend = NFACCT_WARN;
277 cnt->intend = NFACCT_BLOCK;
280 cnt->intend = NFACCT_TETH_COUNTER;
286 STRING_SAVE_COPY(cnt->name, cnt_name);
288 if (cnt->intend == NFACCT_TETH_COUNTER) {
289 char ifname_buf[MAX_IFACE_LENGTH];
291 stc_iface_type_e iface;
292 /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
293 * it's outgoing traffic, due all tethering is mobile databased */
294 iftype_part = strchr(name, ':');
295 ret_value_msg_if(iftype_part == NULL,
296 false, "Invalid format of the tethering counter %s", name);
297 ifname_len = iftype_part - name - 1;
298 strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
299 ifname_buf[ifname_len] = '\0';
300 iface = get_iftype_by_name(ifname_buf);
301 /* check first part is it datacall */
302 if (iface == STC_IFACE_DATACALL) {
303 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
304 cnt->iotype = NFACCT_COUNTER_IN;
306 /* +1, due : symbol and till the end of cnt_name */
307 strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH - 1);
308 iface = get_iftype_by_name(ifname_buf);
309 if (iface == STC_IFACE_DATACALL) {
310 cnt->iotype = NFACCT_COUNTER_OUT;
311 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
315 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
316 STC_LOGE("can't determine tethering direction %s", name);
319 cnt->iftype = STC_IFACE_DATACALL;
320 cnt->classid = STC_TETHERING_APP_CLASSID;
324 io_part = strtok_r(name, "_", &save_ptr);
326 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
330 iftype_part = strtok_r(NULL, "_", &save_ptr);
331 if (iftype_part != NULL)
332 cnt->iftype = convert_to_iftype(atoi(iftype_part));
336 classid_part = strtok_r(NULL, "_", &save_ptr);
337 if (classid_part != NULL)
338 cnt->classid = atoi(classid_part);
340 cnt->classid = STC_ALL_APP_CLASSID;
341 return cnt->intend == NFACCT_BLOCK ? true : false;
344 ifname_part = strtok_r(NULL, "\0", &save_ptr);
345 if (ifname_part != NULL)
346 STRING_SAVE_COPY(cnt->ifname, ifname_part);
353 static void _process_answer(struct netlink_serialization_params *params)
356 struct rtattr *attr_list[__NFACCT_MAX] = {0};
357 struct counter_arg *carg = params->carg;
358 struct genl *ans = params->ans;;
359 struct nlmsghdr *nlhdr = &ans->n;
360 int len = GENLMSG_PAYLOAD(nlhdr);
361 int ans_len = carg->ans_len;
366 /* parse reply message */
367 na = (struct rtattr *)GENLMSG_DATA(ans);
369 while (NLMSG_OK(nlhdr, ans_len)) {
370 fill_attribute_list(attr_list, NFACCT_MAX,
372 if (!attr_list[NFACCT_NAME] ||
373 !attr_list[NFACCT_BYTES])
375 params->eval_attr(attr_list, carg);
378 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
381 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
384 if (params->post_eval_attr)
385 params->post_eval_attr(carg);
388 netlink_serialization_command *
389 netlink_create_command(struct netlink_serialization_params *params)
391 static netlink_serialization_command command = {0,};
392 command.deserialize_answer = _process_answer;
393 command.params = *params;
397 static unsigned int get_args_number(const char *cmd_buf)
400 unsigned int count = 0;
402 for (str = (char *)cmd_buf; *str != '\0'; ++str) {
409 static void wait_for_rule_cmd(pid_t pid)
414 if (!pid || pid == -1) {
415 STC_LOGD("no need to wait");
419 ret_pid = waitpid(pid, &status, 0);
421 char buf[BUF_SIZE_FOR_ERR] = { 0 };
422 STC_LOGD("can't wait for a pid %d %d %s", pid, status,
423 strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
427 stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
429 const size_t args_number = get_args_number(cmd_buf);
432 ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
439 char *args[args_number + 2];
441 char *save_ptr = NULL;
444 STC_LOGD("executing iptables cmd %s in forked process", cmd_buf);
446 args[0] = "iptables";
447 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
449 STC_LOGE("no arguments");
453 for (i = 1; i <= args_number; ++i)
454 args[i] = strtok_r(NULL, " ", &save_ptr);
458 ret = execv(cmd, args);
460 char buf[BUF_SIZE_FOR_ERR] = { 0 };
461 STC_LOGE("Can't execute %s: %s",
462 cmd_buf, strerror_r(errno, buf,
469 return STC_ERROR_NONE;
472 stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
474 const size_t args_number = get_args_number(cmd_buf);
477 ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
484 char *args[args_number + 2];
486 char *save_ptr = NULL;
489 STC_LOGD("executing ip6tables cmd %s in forked process", cmd_buf);
491 args[0] = "ip6tables";
492 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
494 STC_LOGE("no arguments");
498 for (i = 1; i <= args_number; ++i)
499 args[i] = strtok_r(NULL, " ", &save_ptr);
503 ret = execv(cmd, args);
505 char buf[BUF_SIZE_FOR_ERR] = { 0 };
506 STC_LOGE("Can't execute %s: %s",
507 cmd_buf, strerror_r(errno, buf,
514 return STC_ERROR_NONE;
517 static char *choose_iftype_name(nfacct_rule_s *rule)
519 return strlen(rule->ifname) != 0 ? rule->ifname :
520 get_iftype_name(rule->iftype);
523 static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd,
524 const char *chain, const char *nfacct,
525 const char *jump, char *iftype_name,
526 pid_t *pid, nfacct_rule_iptype iptype)
528 char block_buf[MAX_PATH_LENGTH];
530 const char *iptables_type = IPTABLES;
532 ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
533 "Invalid network interface name argument");
535 if (iptype == NFACCT_TYPE_IPV6)
536 iptables_type = IP6TABLES;
538 ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
539 cmd, chain, iftype_name, nfacct, jump);
540 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
541 "Not enough buffer");
543 if (iptype == NFACCT_TYPE_IPV6)
544 exec_ip6tables_cmd(block_buf, pid);
546 exec_iptables_cmd(block_buf, pid);
548 wait_for_rule_cmd(*pid);
550 return STC_ERROR_NONE;
553 static stc_error_e exec_app_cmd(const char *pattern, const char *cmd,
554 const char *nfacct, const char *jump,
555 const uint32_t classid, char *iftype_name,
556 pid_t *pid, nfacct_rule_iptype iptype)
558 char block_buf[MAX_PATH_LENGTH];
560 const char *iptables_type = IPTABLES;
562 ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
563 "Invalid network interface name argument");
565 if (iptype == NFACCT_TYPE_IPV6)
566 iptables_type = IP6TABLES;
568 ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
569 cmd, iftype_name, classid, nfacct, jump);
570 ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
571 "Not enough buffer");
573 if (iptype == NFACCT_TYPE_IPV6)
574 exec_ip6tables_cmd(block_buf, pid);
576 exec_iptables_cmd(block_buf, pid);
578 wait_for_rule_cmd(*pid);
580 return STC_ERROR_NONE;
583 static char *get_iptables_cmd(const nfacct_rule_action action)
585 if (action == NFACCT_ACTION_APPEND)
587 else if (action == NFACCT_ACTION_DELETE)
589 else if (action == NFACCT_ACTION_INSERT)
595 static char *get_iptables_chain(const nfacct_rule_direction iotype)
597 if (iotype == NFACCT_COUNTER_IN)
599 else if (iotype == NFACCT_COUNTER_OUT)
605 static char *get_iptables_jump(const nfacct_rule_jump jump)
607 if (jump == NFACCT_JUMP_ACCEPT)
609 else if (jump == NFACCT_JUMP_REJECT)
615 static stc_error_e produce_app_rule(nfacct_rule_s *rule)
618 return STC_ERROR_INVALID_PARAMETER;
620 char *set_cmd = get_iptables_cmd(rule->action);
621 char *jump_cmd = get_iptables_jump(rule->jump);
622 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
623 3*MAX_DEC_SIZE(int) + 4];
624 stc_error_e ret = STC_ERROR_NONE;
628 if (rule->iotype & NFACCT_COUNTER_IN) {
629 rule->quota = rule->rcv_limit;
630 rule->iotype = NFACCT_COUNTER_IN;
631 generate_counter_name(rule);
633 /* to support quated counter we need nfacct,
634 * don't use it in case of just block without a limit
635 * iow, send_limit = 0 and rcv_limit 0 */
636 if (rule->action != NFACCT_ACTION_DELETE) {
637 ret = nfacct_send_del(rule);
638 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
639 "can't del quota counter");
641 ret = nfacct_send_new(rule);
642 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
643 "can't set nfacct counter");
647 /* we have a counter, let's key in a rule, drop in case of
648 * send_limit/rcv_limit */
649 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
651 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
652 STC_ERROR_FAIL, "Not enought buffer");
654 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
655 rule->classid, choose_iftype_name(rule),
657 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
658 "Can't set conditional block for ingress"
659 " traffic, for classid %u, cmd %s, j %s",
660 rule->classid, set_cmd, jump_cmd);
662 /* remove in any case */
663 if (rule->action == NFACCT_ACTION_DELETE) {
664 /* TODO here and everywhere should be not just a del,
665 * here should be get counted value and than
666 * set new counter with that value, but it's minor issue,
667 * due it's not clear when actual counters was stored,
668 * and based on which value settings made such decition */
669 rule->iptables_rule = nfacct_send_del;
670 set_finalize_flag(rule);
671 nfacct_send_get(rule);
672 ret = nfacct_send_del(rule);
673 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
674 "can't del quota counter");
678 if (rule->iotype & NFACCT_COUNTER_OUT) {
680 rule->iotype = NFACCT_COUNTER_OUT;
681 rule->quota = rule->send_limit;
682 generate_counter_name(rule);
683 if (rule->action != NFACCT_ACTION_DELETE) {
684 ret = nfacct_send_del(rule);
685 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
686 "can't del quota counter");
688 ret = nfacct_send_new(rule);
689 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
690 "can't set quota counter");
694 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
696 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
697 STC_ERROR_FAIL, "Not enought buffer");
699 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
700 rule->classid, choose_iftype_name(rule),
702 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
703 "Can't set conditional block for engress"
704 " traffic, for classid %u, cmd %s, j %s",
705 rule->classid, set_cmd, jump_cmd);
706 if (rule->action == NFACCT_ACTION_DELETE) {
707 rule->iptables_rule = nfacct_send_del;
708 /* not effective, it's better to replace
709 * set_finalize_flag by set_property,
710 * due keep_counter it necessary only for
711 * setting iptables_rule */
712 set_finalize_flag(rule);
713 nfacct_send_get(rule);
714 ret = nfacct_send_del(rule);
715 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
716 "can't del quota counter");
719 return STC_ERROR_NONE;
722 static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
725 return STC_ERROR_INVALID_PARAMETER;
727 char *set_cmd = get_iptables_cmd(rule->action);
728 char *jump_cmd = get_iptables_jump(rule->jump);
729 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
730 3*MAX_DEC_SIZE(int) + 4];
734 if (rule->iotype & NFACCT_COUNTER_IN) {
736 rule->iotype = NFACCT_COUNTER_IN;
737 rule->quota = rule->rcv_limit;
738 generate_counter_name(rule);
740 if (rule->action != NFACCT_ACTION_DELETE) {
741 /* send delete comman in case of creation,
742 * because nfacct doesn't reset value for nfacct quota
743 * in case of quota existing */
744 ret = nfacct_send_del(rule);
745 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
746 "can't del quota counter");
748 ret = nfacct_send_new(rule);
749 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
750 "can't set quota counter");
754 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
755 NFACCT_NAME_MOD, rule->name);
756 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
757 STC_ERROR_FAIL, "Not enought buffer");
759 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
760 get_iptables_chain(rule->iotype),
761 nfacct_buf, jump_cmd,
762 choose_iftype_name(rule), &pid,
764 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
765 "Can't set conditional block for ingress"
766 " traffic, for iftype %d, cmd %s, j %s",
767 rule->iftype, set_cmd, jump_cmd);
770 if (rule->intend == NFACCT_WARN ||
771 rule->intend == NFACCT_BLOCK) {
772 /* RULE_IFACE_OUT is not a misprint here */
773 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
774 FORWARD_RULE, nfacct_buf, jump_cmd,
775 choose_iftype_name(rule), &pid,
777 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
778 "Can't set forward rule for ingress "
779 "traffic, for iftype %d, cmd %s, j %s",
780 rule->iftype, set_cmd, jump_cmd);
784 if (rule->action == NFACCT_ACTION_DELETE) {
785 rule->iptables_rule = nfacct_send_del;
786 set_finalize_flag(rule);
787 nfacct_send_get(rule);
788 ret = nfacct_send_del(rule);
789 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
790 "can't del quota counter");
794 if (rule->iotype & NFACCT_COUNTER_OUT) {
796 rule->iotype = NFACCT_COUNTER_OUT;
797 rule->quota = rule->send_limit;
798 generate_counter_name(rule);
800 if (rule->action != NFACCT_ACTION_DELETE) {
801 /* send delete comman in case of creation,
802 * because nfacct doesn't reset value for nfacct quota
803 * in case of quota existing */
804 ret = nfacct_send_del(rule);
805 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
806 "can't del quota counter");
808 ret = nfacct_send_new(rule);
809 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
810 "can't set quota counter");
814 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
815 NFACCT_NAME_MOD, rule->name);
816 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
817 STC_ERROR_FAIL, "Not enough buffer");
819 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
820 nfacct_buf, jump_cmd,
821 choose_iftype_name(rule), &pid,
823 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
824 "Can't set conditional block for "
825 "engress traffic, for iftype %d, cmd %s, j %s",
826 rule->iftype, set_cmd, jump_cmd);
828 if (rule->intend == NFACCT_WARN ||
829 rule->intend == NFACCT_BLOCK) {
830 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
831 FORWARD_RULE, nfacct_buf, jump_cmd,
832 choose_iftype_name(rule), &pid,
834 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
835 "Can't set forward rule for engress "
836 "traffic, for iftype %d, cmd %s, j %s",
837 rule->iftype, set_cmd, jump_cmd);
841 if (rule->action == NFACCT_ACTION_DELETE) {
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)
855 stc_error_e ret = STC_ERROR_NONE;
858 return STC_ERROR_INVALID_PARAMETER;
860 if (rule->action == NFACCT_ACTION_APPEND &&
861 rule->intend == NFACCT_WARN &&
862 !rule->send_limit && !rule->rcv_limit)
863 return STC_ERROR_NONE;
865 if (rule->classid != STC_ALL_APP_CLASSID &&
866 rule->classid != STC_TETHERING_APP_CLASSID &&
867 rule->classid != STC_TOTAL_DATACALL_CLASSID &&
868 rule->classid != STC_TOTAL_WIFI_CLASSID &&
869 rule->classid != STC_TOTAL_BLUETOOTH_CLASSID &&
870 rule->classid != STC_TOTAL_IPV4_CLASSID &&
871 rule->classid != STC_TOTAL_IPV6_CLASSID)
872 ret = produce_app_rule(rule);
874 ret = produce_iface_rule(rule);
879 void generate_counter_name(nfacct_rule_s *counter)
881 char warn_symbol = 'c';
882 if (!strlen(counter->ifname)) {
883 char *iftype_name = get_iftype_name(counter->iftype);
884 /* trace counter name, maybe name was already generated */
885 ret_msg_if(iftype_name == NULL,
886 "Can't get interface name for counter %s, iftype %d)!",
887 counter->name, counter->iftype);
888 STRING_SAVE_COPY(counter->ifname, iftype_name);
891 if (counter->intend == NFACCT_WARN)
893 else if (counter->intend == NFACCT_BLOCK)
895 snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
896 warn_symbol, counter->iotype, counter->iftype,
897 counter->classid, counter->ifname);