[nfacct-rule] Use heap instead of stack, to aviod large stack usage issue.
[platform/core/connectivity/stc-manager.git] / src / helper / helper-nfacct-rule.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include <arpa/inet.h>
26
27 #include "counter.h"
28 #include "helper-nfacct-rule.h"
29
30 #include "configure_stub.h"
31
32 #define IPTABLES "/usr/sbin/iptables"
33 #define IP6TABLES "/usr/sbin/ip6tables"
34 #define IPTABLES_CHECK "-C"
35 #define APPEND "-A"
36 #define DELETE "-D"
37 #define INSERT "-I"
38
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"
45
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"
49
50 /* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
51
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"
54
55 #define NFNL_SUBSYS_ACCT                7
56 #define BUF_SIZE_FOR_ERR 100
57
58 static void prepare_netlink_msg(struct genl *req, int type, int flag)
59 {
60         int seq = time(NULL);
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;
66 }
67
68 static void add_value_attr(struct genl *req, const void *data, int len,
69                            int type)
70 {
71         int payload;
72         /* get tail */
73         struct nlattr *na = (struct nlattr *)((char *)req +
74                                               NLMSG_ALIGN(req->n.nlmsg_len));
75
76         na->nla_type = type;
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);
81 }
82
83 /*
84  * following 2 function should be used in combination.
85  * start_nest_attr returns nlattr structure, which should be completed by
86  * end_nest_attr,
87  * before these invocations any number of netlink arguments could be inserted
88  * */
89 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
90 {
91         struct nlattr *start = (struct nlattr *)((char *)req +
92                                                  NLMSG_ALIGN(req->n.nlmsg_len));
93
94         start->nla_type = NLA_F_NESTED | type;
95         req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
96         return start;
97 }
98
99 static void end_nest_attr(struct genl *req, struct nlattr *start)
100 {
101         start->nla_len = (__u16)((char *)req +
102                                  NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
103 }
104
105 static void add_string_attr(struct genl *req, const char *str, int type)
106 {
107         add_value_attr(req, str, strlen(str) + 1, type);
108 }
109
110 static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
111 {
112         add_value_attr(req, &v, sizeof(v), type);
113 }
114
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)
117 {
118         add_value_attr(req, &v, sizeof(v), type);
119 }
120
121 static stc_error_e send_nfacct_request(int sock, struct genl *req)
122 {
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);
128
129         return STC_ERROR_NONE;
130 }
131
132 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
133 {
134         int ret = STC_ERROR_NONE;
135         struct genl *req = MALLOC0(struct genl, 1);
136         if (req == NULL) {
137                 STC_LOGE("Failed allocate memory to genl request message");
138                 return STC_ERROR_OUT_OF_MEMORY;
139         }
140
141         prepare_netlink_msg(req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
142         add_string_attr(req, counter->name, NFACCT_NAME);
143
144         if (STC_DEBUG_LOG)
145                 STC_LOGD("counter name %s", counter->name);
146
147         /* padding */
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);
152
153                 add_uint32_attr(req, htobe32(NFACCT_F_QUOTA_BYTES),
154                                 NFACCT_FLAGS);
155                 add_uint64_attr(req, htobe64(counter->quota), NFACCT_QUOTA);
156         }
157
158         ret = send_nfacct_request(counter->carg->sock, req);
159         FREE(req);
160         return ret;
161 }
162
163 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
164 {
165         int ret = STC_ERROR_NONE;
166         struct genl *req = MALLOC0(struct genl, 1);
167         if (req == NULL) {
168                 STC_LOGE("Failed allocate memory to genl request message");
169                 return STC_ERROR_OUT_OF_MEMORY;
170         }
171
172         if (STC_DEBUG_LOG)
173                 STC_LOGD("send remove request for %s", counter->name);
174
175         prepare_netlink_msg(req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
176         add_string_attr(req, counter->name, NFACCT_NAME);
177
178         ret = send_nfacct_request(counter->carg->sock, req);
179         FREE(req);
180         return ret;
181 }
182 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
183
184 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
185                                             enum nfnl_acct_msg_types get_type,
186                                             const char *name,
187                                             int mask, int filter)
188 {
189         int ret = STC_ERROR_NONE;
190         struct nlattr *na;
191         int flag = !name ? NLM_F_DUMP : 0;
192         struct genl *req = MALLOC0(struct genl, 1);
193         if (req == NULL) {
194                 STC_LOGE("Failed allocate memory to genl request message");
195                 return STC_ERROR_OUT_OF_MEMORY;
196         }
197
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 */
201         if (name)
202                 add_string_attr(req, name, NFACCT_NAME);
203
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);
208
209         ret = send_nfacct_request(carg->sock, req);
210         FREE(req);
211         return ret;
212 }
213
214 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
215 {
216         /* get and reset countes value */
217         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
218                                         NFACCT_F_QUOTAS, 0);
219 }
220
221 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
222 {
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);
227 }
228
229 stc_error_e nfacct_send_get_all(struct counter_arg *carg)
230 {
231         /* get and reset everything, used when quiting */
232         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
233                                         0, 0);
234 }
235
236 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
237 {
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);
242
243         return STC_ERROR_INVALID_PARAMETER;
244 }
245
246 static nfacct_rule_direction convert_to_iotype(int type)
247 {
248         return (type < NFACCT_COUNTER_LAST_ELEM &&
249                 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
250 }
251
252 static stc_iface_type_e convert_to_iftype(int type)
253 {
254         return (type < STC_IFACE_LAST_ELEM &&
255                 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
256 }
257
258 bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
259 {
260         char *iftype_part;
261         char *classid_part;
262         char *io_part;
263         char *ifname_part;
264         char *save_ptr = NULL;
265         char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
266
267         strncpy(name, cnt_name, sizeof(name) - 1);
268
269         switch (name[0]) {
270         case 'c':
271                 cnt->intend  = NFACCT_COUNTER;
272                 break;
273         case 'w':
274                 cnt->intend  = NFACCT_WARN;
275                 break;
276         case 'r':
277                 cnt->intend  = NFACCT_BLOCK;
278                 break;
279         case 't':
280                 cnt->intend  = NFACCT_TETH_COUNTER;
281                 break;
282         default:
283                 return false;
284         }
285
286         STRING_SAVE_COPY(cnt->name, cnt_name);
287
288         if (cnt->intend == NFACCT_TETH_COUNTER) {
289                 char ifname_buf[MAX_IFACE_LENGTH];
290                 int ifname_len;
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;
305                 } else {
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);
312                         }
313                 }
314
315                 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
316                         STC_LOGE("can't determine tethering direction %s", name);
317                         return false;
318                 }
319                 cnt->iftype = STC_IFACE_DATACALL;
320                 cnt->classid = STC_TETHERING_APP_CLASSID;
321                 return true;
322         }
323
324         io_part = strtok_r(name, "_", &save_ptr);
325         if (io_part != NULL)
326                 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
327         else
328                 return false;
329
330         iftype_part = strtok_r(NULL, "_", &save_ptr);
331         if (iftype_part != NULL)
332                 cnt->iftype = convert_to_iftype(atoi(iftype_part));
333         else
334                 return false;
335
336         classid_part = strtok_r(NULL, "_", &save_ptr);
337         if (classid_part != NULL)
338                 cnt->classid = atoi(classid_part);
339         else {
340                 cnt->classid = STC_ALL_APP_CLASSID;
341                 return cnt->intend == NFACCT_BLOCK ? true : false;
342         }
343
344         ifname_part = strtok_r(NULL, "\0", &save_ptr);
345         if (ifname_part != NULL)
346                 STRING_SAVE_COPY(cnt->ifname, ifname_part);
347         else
348                 return false;
349
350         return true;
351 }
352
353 static void _process_answer(struct netlink_serialization_params *params)
354 {
355         struct rtattr *na;
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;
362
363         if (len == 0)
364                 return;
365
366         /* parse reply message */
367         na = (struct rtattr *)GENLMSG_DATA(ans);
368
369         while (NLMSG_OK(nlhdr, ans_len)) {
370                 fill_attribute_list(attr_list, NFACCT_MAX,
371                                     na, len);
372                 if (!attr_list[NFACCT_NAME] ||
373                     !attr_list[NFACCT_BYTES])
374                         goto next;
375                 params->eval_attr(attr_list, carg);
376
377 next:
378                 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
379                 if (ans_len < 0)
380                         break;
381                 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
382         }
383
384         if (params->post_eval_attr)
385                 params->post_eval_attr(carg);
386 }
387
388 netlink_serialization_command *
389 netlink_create_command(struct netlink_serialization_params *params)
390 {
391         static netlink_serialization_command command = {0,};
392         command.deserialize_answer = _process_answer;
393         command.params = *params;
394         return &command;
395 }
396
397 static unsigned int get_args_number(const char *cmd_buf)
398 {
399         char *str;
400         unsigned int count = 0;
401
402         for (str = (char *)cmd_buf; *str != '\0'; ++str) {
403                 if (*str == ' ')
404                         ++count;
405         }
406         return count;
407 }
408
409 static void wait_for_rule_cmd(pid_t pid)
410 {
411         int status;
412         pid_t ret_pid;
413
414         if (!pid || pid == -1) {
415                 STC_LOGD("no need to wait");
416                 return;
417         }
418
419         ret_pid = waitpid(pid, &status, 0);
420         if (ret_pid < 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));
424         }
425 }
426
427 stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
428 {
429         const size_t args_number = get_args_number(cmd_buf);
430         *cmd_pid = 0;
431
432         ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
433
434         pid_t pid = fork();
435
436         if (pid == 0) {
437                 char *cmd;
438                 unsigned int i;
439                 char *args[args_number + 2];
440                 int ret;
441                 char *save_ptr = NULL;
442
443                 if (STC_DEBUG_LOG)
444                         STC_LOGD("executing iptables cmd %s in forked process", cmd_buf);
445
446                 args[0] = "iptables";
447                 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
448                 if (cmd == NULL) {
449                         STC_LOGE("no arguments");
450                         exit(-EINVAL);
451                 }
452
453                 for (i = 1; i <= args_number; ++i)
454                         args[i] = strtok_r(NULL, " ", &save_ptr);
455
456                 args[i] = NULL;
457
458                 ret = execv(cmd, args);
459                 if (ret) {
460                         char buf[BUF_SIZE_FOR_ERR] = { 0 };
461                         STC_LOGE("Can't execute %s: %s",
462                                  cmd_buf, strerror_r(errno, buf,
463                                                      BUF_SIZE_FOR_ERR));
464                 }
465                 exit(ret);
466         }
467
468         *cmd_pid = pid;
469         return STC_ERROR_NONE;
470 }
471
472 stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
473 {
474         const size_t args_number = get_args_number(cmd_buf);
475         *cmd_pid = 0;
476
477         ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
478
479         pid_t pid = fork();
480
481         if (pid == 0) {
482                 char *cmd;
483                 unsigned int i;
484                 char *args[args_number + 2];
485                 int ret;
486                 char *save_ptr = NULL;
487
488                 if (STC_DEBUG_LOG)
489                         STC_LOGD("executing ip6tables cmd %s in forked process", cmd_buf);
490
491                 args[0] = "ip6tables";
492                 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
493                 if (cmd == NULL) {
494                         STC_LOGE("no arguments");
495                         exit(-EINVAL);
496                 }
497
498                 for (i = 1; i <= args_number; ++i)
499                         args[i] = strtok_r(NULL, " ", &save_ptr);
500
501                 args[i] = NULL;
502
503                 ret = execv(cmd, args);
504                 if (ret) {
505                         char buf[BUF_SIZE_FOR_ERR] = { 0 };
506                         STC_LOGE("Can't execute %s: %s",
507                                  cmd_buf, strerror_r(errno, buf,
508                                                      BUF_SIZE_FOR_ERR));
509                 }
510                 exit(ret);
511         }
512
513         *cmd_pid = pid;
514         return STC_ERROR_NONE;
515 }
516
517 static char *choose_iftype_name(nfacct_rule_s *rule)
518 {
519         return strlen(rule->ifname) != 0 ? rule->ifname :
520                 get_iftype_name(rule->iftype);
521 }
522
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)
527 {
528         char block_buf[MAX_PATH_LENGTH];
529         int ret;
530         const char *iptables_type = IPTABLES;
531
532         ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
533                          "Invalid network interface name argument");
534
535         if (iptype == NFACCT_TYPE_IPV6)
536                 iptables_type = IP6TABLES;
537
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");
542
543         if (iptype == NFACCT_TYPE_IPV6)
544                 exec_ip6tables_cmd(block_buf, pid);
545         else
546                 exec_iptables_cmd(block_buf, pid);
547
548         wait_for_rule_cmd(*pid);
549
550         return STC_ERROR_NONE;
551 }
552
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)
557 {
558         char block_buf[MAX_PATH_LENGTH];
559         int ret;
560         const char *iptables_type = IPTABLES;
561
562         ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
563                          "Invalid network interface name argument");
564
565         if (iptype == NFACCT_TYPE_IPV6)
566                 iptables_type = IP6TABLES;
567
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");
572
573         if (iptype == NFACCT_TYPE_IPV6)
574                 exec_ip6tables_cmd(block_buf, pid);
575         else
576                 exec_iptables_cmd(block_buf, pid);
577
578         wait_for_rule_cmd(*pid);
579
580         return STC_ERROR_NONE;
581 }
582
583 static char *get_iptables_cmd(const nfacct_rule_action action)
584 {
585         if (action == NFACCT_ACTION_APPEND)
586                 return APPEND;
587         else if (action == NFACCT_ACTION_DELETE)
588                 return DELETE;
589         else if (action == NFACCT_ACTION_INSERT)
590                 return INSERT;
591
592         return "";
593 }
594
595 static char *get_iptables_chain(const nfacct_rule_direction iotype)
596 {
597         if (iotype == NFACCT_COUNTER_IN)
598                 return IN_RULE;
599         else if (iotype == NFACCT_COUNTER_OUT)
600                 return OUT_RULE;
601
602         return "";
603 }
604
605 static char *get_iptables_jump(const nfacct_rule_jump jump)
606 {
607         if (jump == NFACCT_JUMP_ACCEPT)
608                 return ACCEPT_RULE;
609         else if (jump == NFACCT_JUMP_REJECT)
610                 return REJECT_RULE;
611
612         return "";
613 }
614
615 static stc_error_e produce_app_rule(nfacct_rule_s *rule)
616 {
617         if (rule == NULL)
618                 return STC_ERROR_INVALID_PARAMETER;
619
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;
625         pid_t pid = 0;
626
627         /* income part */
628         if (rule->iotype & NFACCT_COUNTER_IN) {
629                 rule->quota = rule->rcv_limit;
630                 rule->iotype = NFACCT_COUNTER_IN;
631                 generate_counter_name(rule);
632
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");
640
641                         ret = nfacct_send_new(rule);
642                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
643                                          "can't set nfacct counter");
644                         keep_counter(rule);
645                 }
646
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,
650                                rule->name);
651                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
652                                  STC_ERROR_FAIL, "Not enought buffer");
653
654                 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
655                                    rule->classid, choose_iftype_name(rule),
656                                    &pid, rule->iptype);
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);
661
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");
675                 }
676         }
677
678         if (rule->iotype & NFACCT_COUNTER_OUT) {
679                 /* outcome part */
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");
687
688                         ret = nfacct_send_new(rule);
689                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
690                                          "can't set quota counter");
691                         keep_counter(rule);
692                 }
693
694                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
695                                rule->name);
696                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
697                                  STC_ERROR_FAIL, "Not enought buffer");
698
699                 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
700                                    rule->classid, choose_iftype_name(rule),
701                                    &pid, rule->iptype);
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");
717                 }
718         }
719         return STC_ERROR_NONE;
720 }
721
722 static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
723 {
724         if (rule == NULL)
725                 return STC_ERROR_INVALID_PARAMETER;
726
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];
731         stc_error_e ret;
732         pid_t pid = 0;
733
734         if (rule->iotype & NFACCT_COUNTER_IN) {
735                 /* income part */
736                 rule->iotype = NFACCT_COUNTER_IN;
737                 rule->quota = rule->rcv_limit;
738                 generate_counter_name(rule);
739
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");
747
748                         ret = nfacct_send_new(rule);
749                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
750                                          "can't set quota counter");
751                         keep_counter(rule);
752                 }
753
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");
758
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,
763                                      rule->iptype);
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);
768
769                 /* for tethering */
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,
776                                              rule->iptype);
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);
781                 }
782                 /* tethering */
783
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");
791                 }
792         }
793
794         if (rule->iotype & NFACCT_COUNTER_OUT) {
795                 /* outcome part */
796                 rule->iotype = NFACCT_COUNTER_OUT;
797                 rule->quota = rule->send_limit;
798                 generate_counter_name(rule);
799
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");
807
808                         ret = nfacct_send_new(rule);
809                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
810                                          "can't set quota counter");
811                         keep_counter(rule);
812                 }
813
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");
818
819                 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
820                                      nfacct_buf, jump_cmd,
821                                      choose_iftype_name(rule), &pid,
822                                      rule->iptype);
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);
827                 /* for tethering  */
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,
833                                              rule->iptype);
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);
838                 }
839                 /* tethering  */
840
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");
848                 }
849         }
850         return STC_ERROR_NONE;
851 }
852
853 stc_error_e produce_net_rule(nfacct_rule_s *rule)
854 {
855         stc_error_e ret = STC_ERROR_NONE;
856
857         if (rule == NULL)
858                 return STC_ERROR_INVALID_PARAMETER;
859
860         if (rule->action == NFACCT_ACTION_APPEND &&
861             rule->intend == NFACCT_WARN &&
862             !rule->send_limit && !rule->rcv_limit)
863                 return STC_ERROR_NONE;
864
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);
873         else
874                 ret = produce_iface_rule(rule);
875
876         return ret;
877 }
878
879 void generate_counter_name(nfacct_rule_s *counter)
880 {
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);
889         }
890
891         if (counter->intend  == NFACCT_WARN)
892                 warn_symbol = 'w';
893         else if (counter->intend  == NFACCT_BLOCK)
894                 warn_symbol = 'r';
895         snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
896                  warn_symbol, counter->iotype, counter->iftype,
897                  counter->classid, counter->ifname);
898 }
899