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"
29 #include "helper-iptables.h"
31 #include "configure_stub.h"
33 #define IPTABLES "/usr/sbin/iptables"
34 #define IP6TABLES "/usr/sbin/ip6tables"
35 #define IPTABLES_CHECK "-C"
40 #define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
41 #define REJECT_RULE "REJECT"
42 #define ACCEPT_RULE "ACCEPT"
43 #define OUT_RULE "OUTPUT"
44 #define IN_RULE "INPUT"
45 #define FORWARD_RULE "FORWARD"
47 /* TODO idea to use the same rule both for BLOCK (REJECT) and WARNING (ACCEPT) */
48 #define RULE_APP_OUT "%s -w %s OUTPUT -o %s -m cgroup --cgroup %u %s %s"
49 #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"
56 #define NFNL_SUBSYS_ACCT 7
57 #define BUF_SIZE_FOR_ERR 100
59 static void prepare_netlink_msg(struct genl *req, int type, int flag)
62 memset(req, 0, sizeof(struct genl));
63 req->n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
64 req->n.nlmsg_type = (NFNL_SUBSYS_ACCT << 8) | type;
65 req->n.nlmsg_flags = NLM_F_REQUEST | flag;
66 req->n.nlmsg_seq = seq;
69 static void add_value_attr(struct genl *req, const void *data, int len,
74 struct nlattr *na = (struct nlattr *)((char *)req +
75 NLMSG_ALIGN(req->n.nlmsg_len));
78 payload = len + NLA_HDRLEN;
79 na->nla_len = payload;
80 memcpy(NLA_DATA(na), data, len);
81 req->n.nlmsg_len += NLMSG_ALIGN(payload);
85 * following 2 function should be used in combination.
86 * start_nest_attr returns nlattr structure, which should be completed by
88 * before these invocations any number of netlink arguments could be inserted
90 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
92 struct nlattr *start = (struct nlattr *)((char *)req +
93 NLMSG_ALIGN(req->n.nlmsg_len));
95 start->nla_type = NLA_F_NESTED | type;
96 req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
100 static void end_nest_attr(struct genl *req, struct nlattr *start)
102 start->nla_len = (__u16)((char *)req +
103 NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
106 static void add_string_attr(struct genl *req, const char *str, int type)
108 add_value_attr(req, str, strlen(str) + 1, type);
111 static void add_uint64_attr(struct genl *req, const long long unsigned int v, int type)
113 add_value_attr(req, &v, sizeof(v), type);
116 /* macros or templare, due uint64 and uint32 is the same functions */
117 static void add_uint32_attr(struct genl *req, const uint32_t v, int type)
119 add_value_attr(req, &v, sizeof(v), type);
122 static stc_error_e send_nfacct_request(int sock, struct genl *req)
124 struct sockaddr_nl nladdr = {.nl_family = AF_NETLINK};
125 int ret = sendto(sock, (char *)(&req->n), req->n.nlmsg_len, 0,
126 (struct sockaddr *)&nladdr, sizeof(nladdr));
127 ret_value_msg_if(ret < 0, STC_ERROR_FAIL,
128 "Failed to send nfacct request, error [%d]", ret);
130 return STC_ERROR_NONE;
133 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
135 int ret = STC_ERROR_NONE;
136 struct genl *req = MALLOC0(struct genl, 1);
138 STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
139 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
142 prepare_netlink_msg(req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
143 add_string_attr(req, counter->name, NFACCT_NAME);
146 add_uint64_attr(req, 0, NFACCT_PKTS);
147 add_uint64_attr(req, 0, NFACCT_BYTES);
149 if (counter->quota) {
150 STC_LOGD("quota bytes %lld", counter->quota);
152 add_uint32_attr(req, htobe32(NFACCT_F_QUOTA_BYTES),
154 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"); //LCOV_EXCL_LINE
169 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
172 prepare_netlink_msg(req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
173 add_string_attr(req, counter->name, NFACCT_NAME);
175 ret = send_nfacct_request(counter->carg->sock, req);
179 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
181 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
182 enum nfnl_acct_msg_types get_type,
184 int mask, int filter)
186 int ret = STC_ERROR_NONE;
188 int flag = !name ? NLM_F_DUMP : 0;
189 struct genl *req = MALLOC0(struct genl, 1);
191 STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
192 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
195 prepare_netlink_msg(req, get_type, flag);
196 /* due we don't get counter with quota any where else,
197 * here we will request just counters by default */
199 add_string_attr(req, name, NFACCT_NAME);
201 na = start_nest_attr(req, NFACCT_FILTER);
202 add_uint32_attr(req, htonl(mask), NFACCT_FILTER_ATTR_MASK);
203 add_uint32_attr(req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
204 end_nest_attr(req, na);
206 ret = send_nfacct_request(carg->sock, req);
211 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
213 /* get and reset countes value */
214 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
218 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
220 /* just get counters */
221 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name,
222 NFACCT_F_QUOTA_BYTES,
223 NFACCT_F_QUOTA_BYTES);
226 API stc_error_e nfacct_send_get_all(struct counter_arg *carg)
228 /* get and reset everything, used when quiting */
229 return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
233 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
235 if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
236 return nfacct_send_get_quotas(rule->carg, rule->name);
237 else if (rule->intend == NFACCT_COUNTER)
238 return nfacct_send_get_counters(rule->carg, rule->name);
240 return STC_ERROR_INVALID_PARAMETER;
243 static nfacct_rule_direction convert_to_iotype(int type)
245 return (type < NFACCT_COUNTER_LAST_ELEM &&
246 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
249 static stc_iface_type_e convert_to_iftype(int type)
251 return (type < STC_IFACE_LAST_ELEM &&
252 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
255 API bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
261 char *save_ptr = NULL;
262 char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
264 strncpy(name, cnt_name, sizeof(name) - 1);
268 cnt->intend = NFACCT_COUNTER;
271 cnt->intend = NFACCT_WARN;
274 cnt->intend = NFACCT_BLOCK;
277 cnt->intend = NFACCT_ALLOW;
280 cnt->intend = NFACCT_TETH_COUNTER; //LCOV_EXCL_LINE
281 break; //LCOV_EXCL_LINE
286 STRING_SAVE_COPY(cnt->name, cnt_name);
289 /* ========================================================
291 * Below parsing for tethering case is not in use
292 * stc-manager needs to ignore this for NFACCT_TETH_COUNTER
293 * this is disbaled for future use.
294 * =======================================================*/
297 if (cnt->intend == NFACCT_TETH_COUNTER) {
298 char ifname_buf[MAX_IFACE_LENGTH];
300 stc_iface_type_e iface;
301 /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
302 * it's outgoing traffic, due all tethering is mobile databased */
303 iftype_part = strchr(name, ':');
304 ret_value_msg_if(iftype_part == NULL,
305 false, "Invalid format of the tethering counter %s", name);
306 ifname_len = iftype_part - name - 1;
307 strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
308 ifname_buf[ifname_len] = '\0';
309 iface = get_iftype_by_name(ifname_buf);
310 /* check first part is it datacall */
311 if (iface == STC_IFACE_DATACALL) {
312 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
313 cnt->iotype = NFACCT_COUNTER_IN;
315 /* +1, due : symbol and till the end of cnt_name */
316 strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH - 1);
317 iface = get_iftype_by_name(ifname_buf);
318 if (iface == STC_IFACE_DATACALL) {
319 cnt->iotype = NFACCT_COUNTER_OUT;
320 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
324 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
325 STC_LOGE("can't determine tethering direction %s", name);
328 cnt->iftype = STC_IFACE_DATACALL;
329 cnt->classid = STC_TETHERING_APP_CLASSID;
335 io_part = strtok_r(name, "_", &save_ptr);
337 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
341 iftype_part = strtok_r(NULL, "_", &save_ptr);
342 if (iftype_part != NULL)
343 cnt->iftype = convert_to_iftype(atoi(iftype_part));
347 classid_part = strtok_r(NULL, "_", &save_ptr);
348 if (classid_part != NULL)
349 cnt->classid = atoi(classid_part);
351 cnt->classid = STC_ALL_APP_CLASSID;
352 return cnt->intend == NFACCT_BLOCK ? true : false;
355 ifname_part = strtok_r(NULL, "\0", &save_ptr);
356 if (ifname_part != NULL)
357 STRING_SAVE_COPY(cnt->ifname, ifname_part);
364 static void _process_answer(struct netlink_serialization_params *params)
367 struct rtattr *attr_list[__NFACCT_MAX] = {0};
368 struct counter_arg *carg = params->carg;
369 struct genl *ans = params->ans;;
370 struct nlmsghdr *nlhdr = &ans->n;
371 int len = GENLMSG_PAYLOAD(nlhdr);
372 int ans_len = carg->ans_len;
377 /* parse reply message */
378 na = (struct rtattr *)GENLMSG_DATA(ans);
380 while (NLMSG_OK(nlhdr, ans_len)) {
381 fill_attribute_list(attr_list, NFACCT_MAX,
383 if (!attr_list[NFACCT_NAME] ||
384 !attr_list[NFACCT_BYTES])
386 params->eval_attr(attr_list, carg);
389 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
392 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
395 if (params->post_eval_attr)
396 params->post_eval_attr(carg);
399 API netlink_serialization_command *
400 netlink_create_command(struct netlink_serialization_params *params)
402 static netlink_serialization_command command = {0,};
403 command.deserialize_answer = _process_answer;
404 command.params = *params;
408 static char *get_iptables_cmd(const nfacct_rule_action action)
410 if (action == NFACCT_ACTION_APPEND)
412 else if (action == NFACCT_ACTION_DELETE)
414 else if (action == NFACCT_ACTION_INSERT)
420 static char *get_iptables_chain(uint32_t classid,
421 const nfacct_rule_direction iotype,
422 const stc_app_state_e app_state,
423 const nfacct_rule_intend intend)
425 if (iotype == NFACCT_COUNTER_IN) {
426 if (intend == NFACCT_COUNTER ||
427 intend == NFACCT_TETH_COUNTER) {
428 if (app_state == STC_APP_STATE_FOREGROUND)
429 return STC_IN_FG_CHAIN;
431 return STC_IN_BG_CHAIN;
432 } else if (intend == NFACCT_ALLOW ||
433 intend == NFACCT_TETH_ALLOW) {
434 return STC_IN_ACCEPT_CHAIN;
436 if (classid == STC_BACKGROUND_APP_CLASSID)
437 return STC_IN_BG_DROP_CHAIN;
439 return STC_IN_DROP_CHAIN;
441 } else if (iotype == NFACCT_COUNTER_OUT) {
442 if (intend == NFACCT_COUNTER ||
443 intend == NFACCT_TETH_COUNTER) {
444 if (app_state == STC_APP_STATE_FOREGROUND)
445 return STC_OUT_FG_CHAIN;
447 return STC_OUT_BG_CHAIN;
448 } else if (intend == NFACCT_ALLOW ||
449 intend == NFACCT_TETH_ALLOW) {
450 return STC_OUT_ACCEPT_CHAIN;
452 if (classid == STC_BACKGROUND_APP_CLASSID)
453 return STC_OUT_BG_DROP_CHAIN;
455 return STC_OUT_DROP_CHAIN;
457 } else if (iotype == NFACCT_COUNTER_FORWARD)
458 return STC_FRWD_CHAIN;
463 static char *get_iptables_jump(const nfacct_rule_jump jump)
465 if (jump == NFACCT_JUMP_ACCEPT)
467 else if (jump == NFACCT_JUMP_REJECT)
474 static char *choose_iftype_name(nfacct_rule_s *rule)
476 return strlen(rule->ifname) != 0 ? rule->ifname :
477 get_iftype_name(rule->iftype);
481 static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
483 stc_error_e ret = STC_ERROR_NONE;
484 iptables_ip_type_e iptype;
485 iptables_rule_s iptables_rule;
486 memset(&iptables_rule, 0, sizeof(iptables_rule_s));
488 iptables_rule.nfacct_name = g_strdup(rule->name);
489 iptables_rule.ifname = g_strdup(rule->ifname);
490 iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
492 /* In case of tehering rules use chain 'STC_TETHER' */
493 if (rule->intend == NFACCT_TETH_COUNTER ||
494 rule->intend == NFACCT_TETH_ALLOW ||
495 rule->intend == NFACCT_TETH_BLOCK)
496 iptables_rule.chain = g_strdup(STC_TETHER_CHAIN);
498 iptables_rule.chain = g_strdup(get_iptables_chain(rule->classid,
499 rule->iotype, rule->app_state, rule->intend));
501 if (rule->classid < STC_RESERVED_CLASSID_MAX)
502 iptables_rule.classid = STC_UNKNOWN_CLASSID;
504 iptables_rule.classid = rule->classid;
505 iptables_rule.direction = (rule->iotype & NFACCT_COUNTER_IN) ?
506 IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
507 iptype = (iptables_ip_type_e)rule->iptype;
509 /* specify the ip range type for source and destination */
510 iptables_rule.s_iprange_type = rule->src_iprange_type;
511 iptables_rule.d_iprange_type = rule->dst_iprange_type;
513 /* specify source and destination ip address if any */
515 if (!inet_aton(rule->src_ip1, &iptables_rule.s_ip1)) {
516 ret = STC_ERROR_INVALID_PARAMETER;
522 if (!inet_aton(rule->src_ip2, &iptables_rule.s_ip2)) {
523 ret = STC_ERROR_INVALID_PARAMETER;
529 if (!inet_aton(rule->dst_ip1, &iptables_rule.d_ip1)) {
530 ret = STC_ERROR_INVALID_PARAMETER;
536 if (!inet_aton(rule->dst_ip2, &iptables_rule.d_ip2)) {
537 ret = STC_ERROR_INVALID_PARAMETER;
542 if (rule->action == NFACCT_ACTION_DELETE) {
543 /* delete interface rule */
544 ret = iptables_remove(&iptables_rule, iptype);
546 /* add interface rule */
547 ret = iptables_add(&iptables_rule, iptype);
551 g_free(iptables_rule.nfacct_name);
552 g_free(iptables_rule.ifname);
553 g_free(iptables_rule.target);
554 g_free(iptables_rule.chain);
559 static stc_error_e produce_app_rule(nfacct_rule_s *rule)
562 return STC_ERROR_INVALID_PARAMETER;
564 char *set_cmd = get_iptables_cmd(rule->action);
565 char *jump_cmd = get_iptables_jump(rule->jump);
566 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
567 3*MAX_DEC_SIZE(int) + 4 + 1];
568 stc_error_e ret = STC_ERROR_NONE;
569 uint32_t classid = rule->classid;
572 if (rule->iotype & NFACCT_COUNTER_IN) {
573 rule->quota = rule->rcv_limit;
574 rule->iotype = NFACCT_COUNTER_IN;
575 generate_counter_name(rule);
577 /* to support quated counter we need nfacct,
578 * don't use it in case of just block without a limit
579 * iow, send_limit = 0 and rcv_limit 0 */
580 if (rule->action != NFACCT_ACTION_DELETE) {
581 ret = nfacct_send_del(rule);
582 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
583 "can't del quota counter");
585 ret = nfacct_send_new(rule);
586 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
587 "can't set nfacct counter");
591 /* we have a counter, let's key in a rule, drop in case of
592 * send_limit/rcv_limit */
593 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
595 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
596 STC_ERROR_FAIL, "Not enought buffer");
598 /* cgroup extention on FORWARD chain are not allowed
599 * remove classid info in case of tethering rules */
600 if (rule->intend == NFACCT_TETH_COUNTER ||
601 rule->intend == NFACCT_TETH_ALLOW ||
602 rule->intend == NFACCT_TETH_BLOCK) {
603 classid = rule->classid;
607 ret = exec_iptables_cmd(rule);
609 /* restore the classid info in case of tethering rule */
610 if (rule->intend == NFACCT_TETH_COUNTER ||
611 rule->intend == NFACCT_TETH_ALLOW ||
612 rule->intend == NFACCT_TETH_BLOCK)
613 rule->classid = classid;
615 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
616 "Can't set conditional block for ingress"
617 " traffic, for classid %u, cmd %s, j %s",
618 rule->classid, set_cmd, jump_cmd);
620 /* remove in any case */
621 if (rule->action == NFACCT_ACTION_DELETE) {
622 /* TODO here and everywhere should be not just a del,
623 * here should be get counted value and than
624 * set new counter with that value, but it's minor issue,
625 * due it's not clear when actual counters was stored,
626 * and based on which value settings made such decition */
627 rule->iptables_rule = nfacct_send_del;
628 set_finalize_flag(rule);
629 nfacct_send_get(rule);
630 ret = nfacct_send_del(rule);
631 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
632 "can't del quota counter");
636 if (rule->iotype & NFACCT_COUNTER_OUT) {
638 rule->iotype = NFACCT_COUNTER_OUT;
639 rule->quota = rule->send_limit;
640 generate_counter_name(rule);
641 if (rule->action != NFACCT_ACTION_DELETE) {
642 ret = nfacct_send_del(rule);
643 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
644 "can't del quota counter");
646 ret = nfacct_send_new(rule);
647 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
648 "can't set quota counter");
652 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
654 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
655 STC_ERROR_FAIL, "Not enought buffer");
657 /* cgroup extention on FORWARD chain are not allowed
658 * remove classid info in case of tethering rules */
659 if (rule->intend == NFACCT_TETH_COUNTER ||
660 rule->intend == NFACCT_TETH_ALLOW ||
661 rule->intend == NFACCT_TETH_BLOCK) {
662 classid = rule->classid;
666 ret = exec_iptables_cmd(rule);
668 /* restore the classid info in case of tethering rule */
669 if (rule->intend == NFACCT_TETH_COUNTER ||
670 rule->intend == NFACCT_TETH_ALLOW ||
671 rule->intend == NFACCT_TETH_BLOCK)
672 rule->classid = classid;
674 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
675 "Can't set conditional block for engress"
676 " traffic, for classid %u, cmd %s, j %s",
677 rule->classid, set_cmd, jump_cmd);
679 if (rule->action == NFACCT_ACTION_DELETE) {
680 rule->iptables_rule = nfacct_send_del;
681 /* not effective, it's better to replace
682 * set_finalize_flag by set_property,
683 * due keep_counter it necessary only for
684 * setting iptables_rule */
685 set_finalize_flag(rule);
686 nfacct_send_get(rule);
687 ret = nfacct_send_del(rule);
688 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
689 "can't del quota counter");
692 return STC_ERROR_NONE;
695 static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
698 return STC_ERROR_INVALID_PARAMETER;
700 char *set_cmd = get_iptables_cmd(rule->action);
701 char *jump_cmd = get_iptables_jump(rule->jump);
702 char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
703 3*MAX_DEC_SIZE(int) + 4 + 1];
706 if (rule->iotype & NFACCT_COUNTER_IN) {
708 rule->iotype = NFACCT_COUNTER_IN;
709 rule->quota = rule->rcv_limit;
710 generate_counter_name(rule);
712 if (rule->action != NFACCT_ACTION_DELETE) {
713 /* send delete comman in case of creation,
714 * because nfacct doesn't reset value for nfacct quota
715 * in case of quota existing */
716 ret = nfacct_send_del(rule);
717 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
718 "can't del quota counter");
720 ret = nfacct_send_new(rule);
721 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
722 "can't set quota counter");
726 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
727 NFACCT_NAME_MOD, rule->name);
728 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
729 STC_ERROR_FAIL, "Not enought buffer");
731 ret = exec_iptables_cmd(rule);
732 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
733 "Can't set conditional block for ingress"
734 " traffic, for iftype %d, cmd %s, j %s",
735 rule->iftype, set_cmd, jump_cmd);
739 if (rule->intend == NFACCT_WARN ||
740 rule->intend == NFACCT_BLOCK) {
741 /* RULE_IFACE_OUT is not a misprint here */
742 nfacct_rule_direction temp_iotype = rule->iotype;
744 rule->iotype = NFACCT_COUNTER_FORWARD;
745 ret = exec_iptables_cmd(rule);
746 rule->iotype = temp_iotype;
747 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
748 "Can't set forward rule for ingress "
749 "traffic, for iftype %d, cmd %s, j %s",
750 rule->iftype, set_cmd, jump_cmd);
754 if (rule->action == NFACCT_ACTION_DELETE) {
755 rule->iptables_rule = nfacct_send_del;
756 set_finalize_flag(rule);
757 nfacct_send_get(rule);
758 ret = nfacct_send_del(rule);
759 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
760 "can't del quota counter");
765 if (rule->iotype & NFACCT_COUNTER_OUT) {
767 rule->iotype = NFACCT_COUNTER_OUT;
768 rule->quota = rule->send_limit;
769 generate_counter_name(rule);
771 if (rule->action != NFACCT_ACTION_DELETE) {
772 /* send delete comman in case of creation,
773 * because nfacct doesn't reset value for nfacct quota
774 * in case of quota existing */
775 ret = nfacct_send_del(rule);
776 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
777 "can't del quota counter");
779 ret = nfacct_send_new(rule);
780 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
781 "can't set quota counter");
785 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
786 NFACCT_NAME_MOD, rule->name);
787 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
788 STC_ERROR_FAIL, "Not enough buffer");
790 ret = exec_iptables_cmd(rule);
791 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
792 "Can't set conditional block for "
793 "engress traffic, for iftype %d, cmd %s, j %s",
794 rule->iftype, set_cmd, jump_cmd);
798 if (rule->intend == NFACCT_WARN ||
799 rule->intend == NFACCT_BLOCK) {
800 nfacct_rule_direction temp_iotype = rule->iotype;
802 rule->iotype = NFACCT_COUNTER_OUT;
803 ret = exec_iptables_cmd(rule);
804 rule->iotype = temp_iotype;
805 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
806 "Can't set forward rule for engress "
807 "traffic, for iftype %d, cmd %s, j %s",
808 rule->iftype, set_cmd, jump_cmd);
812 if (rule->action == NFACCT_ACTION_DELETE) {
813 rule->iptables_rule = nfacct_send_del;
814 set_finalize_flag(rule);
815 nfacct_send_get(rule);
816 ret = nfacct_send_del(rule);
817 ret_value_msg_if(ret != STC_ERROR_NONE, ret,
818 "can't del quota counter");
823 return STC_ERROR_NONE;
826 API stc_error_e produce_net_rule(nfacct_rule_s *rule)
828 stc_error_e ret = STC_ERROR_NONE;
831 return STC_ERROR_INVALID_PARAMETER;
833 if (rule->action == NFACCT_ACTION_APPEND &&
834 rule->intend == NFACCT_WARN &&
835 !rule->send_limit && !rule->rcv_limit)
836 return STC_ERROR_NONE;
838 if (rule->classid != STC_ALL_APP_CLASSID &&
839 rule->classid != STC_TETHERING_APP_CLASSID &&
840 rule->classid != STC_BACKGROUND_APP_CLASSID &&
841 rule->classid != STC_TOTAL_DATACALL_CLASSID &&
842 rule->classid != STC_TOTAL_WIFI_CLASSID &&
843 rule->classid != STC_TOTAL_BLUETOOTH_CLASSID &&
844 rule->classid != STC_TOTAL_IPV4_CLASSID &&
845 rule->classid != STC_TOTAL_IPV6_CLASSID)
846 ret = produce_app_rule(rule);
848 ret = produce_iface_rule(rule);
853 static stc_error_e append_iptables_cmd(GSList **iptables_list, nfacct_rule_s *rule)
855 iptables_rule_s *iptables_rule = NULL;
857 iptables_rule = MALLOC0(iptables_rule_s, 1);
859 return STC_ERROR_OUT_OF_MEMORY;
861 iptables_rule->nfacct_name = g_strdup(rule->name);
862 iptables_rule->ifname = g_strdup(rule->ifname);
863 iptables_rule->target = g_strdup(get_iptables_jump(rule->jump));
864 iptables_rule->chain = g_strdup(get_iptables_chain(rule->classid,
865 rule->iotype, rule->app_state, rule->intend));
866 if (rule->classid < STC_RESERVED_CLASSID_MAX)
867 iptables_rule->classid = STC_UNKNOWN_CLASSID;
869 iptables_rule->classid = rule->classid;
870 iptables_rule->direction = (rule->iotype & NFACCT_COUNTER_IN) ?
871 IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
873 *iptables_list = g_slist_append(*iptables_list, iptables_rule);
875 return STC_ERROR_NONE;
878 static void iptables_list_free(gpointer value)
880 iptables_rule_s *iptables_rule = (iptables_rule_s *)value;
882 g_free(iptables_rule->chain);
883 g_free(iptables_rule->nfacct_name);
884 g_free(iptables_rule->ifname);
885 g_free(iptables_rule->target);
886 g_free(iptables_rule);
889 API stc_error_e produce_net_list(GSList *rule_list,
890 nfacct_rule_iptype iptype, nfacct_rule_action action)
893 GSList *iptables_list = NULL;
894 stc_error_e ret = STC_ERROR_NONE;
896 for (list = rule_list; list; list = list->next) {
897 nfacct_rule_s *rule = list->data;
899 if (rule->action == NFACCT_ACTION_APPEND &&
900 rule->intend == NFACCT_WARN &&
901 !rule->send_limit && !rule->rcv_limit)
904 generate_counter_name(rule);
905 if (rule->action != NFACCT_ACTION_DELETE) {
906 ret = nfacct_send_del(rule);
907 if (ret != STC_ERROR_NONE)
910 ret = nfacct_send_new(rule);
911 if (ret != STC_ERROR_NONE)
915 append_iptables_cmd(&iptables_list, rule);
918 if (action == NFACCT_ACTION_INSERT ||
919 action == NFACCT_ACTION_APPEND)
920 ret = iptables_add_list(iptables_list, iptype);
921 else if (action == NFACCT_ACTION_DELETE)
922 ret = iptables_remove_list(iptables_list, iptype);
924 for (list = rule_list; list; list = list->next) {
925 nfacct_rule_s *rule = list->data;
927 if (rule->action == NFACCT_ACTION_DELETE)
928 nfacct_send_del(rule);
931 g_slist_free_full(iptables_list, iptables_list_free);
935 void generate_counter_name(nfacct_rule_s *counter)
937 char warn_symbol = 'c';
938 if (!strlen(counter->ifname)) {
939 char *iftype_name = get_iftype_name(counter->iftype);
940 /* trace counter name, maybe name was already generated */
941 ret_msg_if(iftype_name == NULL,
942 "Can't get interface name for counter %s, iftype %d)!",
943 counter->name, counter->iftype);
944 STRING_SAVE_COPY(counter->ifname, iftype_name);
947 if (counter->intend == NFACCT_WARN ||
948 counter->intend == NFACCT_TETH_WARN)
950 else if (counter->intend == NFACCT_BLOCK ||
951 counter->intend == NFACCT_TETH_BLOCK)
953 else if (counter->intend == NFACCT_ALLOW ||
954 counter->intend == NFACCT_TETH_ALLOW)
956 else if (counter->intend == NFACCT_TETH_COUNTER)
958 snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
959 warn_symbol, counter->iotype, counter->iftype,
960 counter->classid, counter->ifname);