Ignoring values of TOTAL_* details when fetching interface data.
[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         struct genl req;
135
136         prepare_netlink_msg(&req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
137         add_string_attr(&req, counter->name, NFACCT_NAME);
138
139         STC_LOGD("counter name %s", counter->name);
140
141         /* padding */
142         add_uint64_attr(&req, 0, NFACCT_PKTS);
143         add_uint64_attr(&req, 0, NFACCT_BYTES);
144         if (counter->quota) {
145                 STC_LOGD("quota bytes %"PRId64, counter->quota);
146
147                 add_uint32_attr(&req, htobe32(NFACCT_F_QUOTA_BYTES),
148                                 NFACCT_FLAGS);
149                 add_uint64_attr(&req, htobe64(counter->quota), NFACCT_QUOTA);
150         }
151
152         return send_nfacct_request(counter->carg->sock, &req);
153 }
154
155 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
156 {
157         struct genl req;
158
159         STC_LOGD("send remove request for %s", counter->name);
160
161         prepare_netlink_msg(&req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
162         add_string_attr(&req, counter->name, NFACCT_NAME);
163         return send_nfacct_request(counter->carg->sock, &req);
164 }
165 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
166
167 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
168                                             enum nfnl_acct_msg_types get_type,
169                                             const char *name,
170                                             int mask, int filter)
171 {
172         struct genl req;
173         struct nlattr *na;
174         int flag = !name ? NLM_F_DUMP : 0;
175         prepare_netlink_msg(&req, get_type,
176                             flag);
177         /* due we don't get counter with quota any where else,
178          * here we will request just counters by default */
179         if (name)
180                 add_string_attr(&req, name, NFACCT_NAME);
181
182         na = start_nest_attr(&req, NFACCT_FILTER);
183         add_uint32_attr(&req, htonl(mask),
184                         NFACCT_FILTER_ATTR_MASK);
185         add_uint32_attr(&req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
186         end_nest_attr(&req, na);
187         return send_nfacct_request(carg->sock, &req);
188 }
189
190 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
191 {
192         /* get and reset countes value */
193         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
194                                         NFACCT_F_QUOTAS, 0);
195 }
196
197 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
198 {
199         /* just get counters */
200         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name,
201                                         NFACCT_F_QUOTA_BYTES,
202                                         NFACCT_F_QUOTA_BYTES);
203 }
204
205 stc_error_e nfacct_send_get_all(struct counter_arg *carg)
206 {
207         /* get and reset everything, used when quiting */
208         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
209                                         0, 0);
210 }
211
212 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
213 {
214         if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
215                 return nfacct_send_get_quotas(rule->carg, rule->name);
216         else if (rule->intend == NFACCT_COUNTER)
217                 return nfacct_send_get_counters(rule->carg, rule->name);
218
219         return STC_ERROR_INVALID_PARAMETER;
220 }
221
222 static nfacct_rule_direction convert_to_iotype(int type)
223 {
224         return (type < NFACCT_COUNTER_LAST_ELEM &&
225                 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
226 }
227
228 static stc_iface_type_e convert_to_iftype(int type)
229 {
230         return (type < STC_IFACE_LAST_ELEM &&
231                 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
232 }
233
234 bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
235 {
236         char *iftype_part;
237         char *classid_part;
238         char *io_part;
239         char *ifname_part;
240         char *save_ptr = NULL;
241         char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
242
243         strncpy(name, cnt_name, sizeof(name) - 1);
244
245         switch (name[0]) {
246         case 'c':
247                 cnt->intend  = NFACCT_COUNTER;
248                 break;
249         case 'w':
250                 cnt->intend  = NFACCT_WARN;
251                 break;
252         case 'r':
253                 cnt->intend  = NFACCT_BLOCK;
254                 break;
255         case 't':
256                 cnt->intend  = NFACCT_TETH_COUNTER;
257                 break;
258         default:
259                 return false;
260         }
261
262         STRING_SAVE_COPY(cnt->name, cnt_name);
263
264         if (cnt->intend == NFACCT_TETH_COUNTER) {
265                 char ifname_buf[MAX_IFACE_LENGTH];
266                 int ifname_len;
267                 stc_iface_type_e iface;
268                 /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
269                  * it's outgoing traffic, due all tethering is mobile databased */
270                 iftype_part = strchr(name, ':');
271                 ret_value_msg_if(iftype_part == NULL,
272                                  false, "Invalid format of the tethering counter %s", name);
273                 ifname_len = iftype_part - name - 1;
274                 strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
275                 ifname_buf[ifname_len] = '\0';
276                 iface = get_iftype_by_name(ifname_buf);
277                 /* check first part is it datacall */
278                 if (iface == STC_IFACE_DATACALL) {
279                         strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
280                         cnt->iotype = NFACCT_COUNTER_IN;
281                 } else {
282                         /* +1, due : symbol and till the end of cnt_name */
283                         strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH);
284                         iface = get_iftype_by_name(ifname_buf);
285                         if (iface == STC_IFACE_DATACALL) {
286                                 cnt->iotype = NFACCT_COUNTER_OUT;
287                                 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH);
288                         }
289                 }
290
291                 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
292                         STC_LOGE("can't determine tethering direction %s", name);
293                         return false;
294                 }
295                 cnt->iftype = STC_IFACE_DATACALL;
296                 cnt->classid = STC_TETHERING_APP_CLASSID;
297                 return true;
298         }
299
300         io_part = strtok_r(name, "_", &save_ptr);
301         if (io_part != NULL)
302                 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
303         else
304                 return false;
305
306         iftype_part = strtok_r(NULL, "_", &save_ptr);
307         if (iftype_part != NULL)
308                 cnt->iftype = convert_to_iftype(atoi(iftype_part));
309         else
310                 return false;
311
312         classid_part = strtok_r(NULL, "_", &save_ptr);
313         if (classid_part != NULL)
314                 cnt->classid = atoi(classid_part);
315         else {
316                 cnt->classid = STC_ALL_APP_CLASSID;
317                 return cnt->intend == NFACCT_BLOCK ? true : false;
318         }
319
320         ifname_part = strtok_r(NULL, "\0", &save_ptr);
321         if (ifname_part != NULL)
322                 STRING_SAVE_COPY(cnt->ifname, ifname_part);
323         else
324                 return false;
325
326         return true;
327 }
328
329 static void _process_answer(struct netlink_serialization_params *params)
330 {
331         struct rtattr *na;
332         struct rtattr *attr_list[__NFACCT_MAX] = {0};
333         struct counter_arg *carg = params->carg;
334         struct genl *ans = params->ans;;
335         struct nlmsghdr *nlhdr = &ans->n;
336         int len = GENLMSG_PAYLOAD(nlhdr);
337         int ans_len = carg->ans_len;
338
339         if (len == 0)
340                 return;
341
342         /* parse reply message */
343         na = (struct rtattr *)GENLMSG_DATA(ans);
344
345         while (NLMSG_OK(nlhdr, ans_len)) {
346                 fill_attribute_list(attr_list, NFACCT_MAX,
347                                     na, len);
348                 if (!attr_list[NFACCT_NAME] ||
349                     !attr_list[NFACCT_BYTES])
350                         goto next;
351                 params->eval_attr(attr_list, carg);
352
353 next:
354                 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
355                 if (ans_len < 0)
356                         break;
357                 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
358         }
359
360         if (params->post_eval_attr)
361                 params->post_eval_attr(carg);
362 }
363
364 netlink_serialization_command *
365 netlink_create_command(struct netlink_serialization_params *params)
366 {
367         static netlink_serialization_command command = {0,};
368         command.deserialize_answer = _process_answer;
369         command.params = *params;
370         return &command;
371 }
372
373 static unsigned int get_args_number(const char *cmd_buf)
374 {
375         char *str;
376         unsigned int count = 0;
377
378         for (str = (char *)cmd_buf; *str != '\0'; ++str) {
379                 if (*str == ' ')
380                         ++count;
381         }
382         return count;
383 }
384
385 static void wait_for_rule_cmd(pid_t pid)
386 {
387         int status;
388         pid_t ret_pid;
389
390         if (!pid || pid == -1) {
391                 STC_LOGD("no need to wait");
392                 return;
393         }
394
395         ret_pid = waitpid(pid, &status, 0);
396         if (ret_pid < 0) {
397                 char buf[BUF_SIZE_FOR_ERR] = { 0 };
398                 STC_LOGD("can't wait for a pid %d %d %s", pid, status,
399                          strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
400         }
401 }
402
403 static char* get_cmd_pos(const char *cmd_buf)
404 {
405         char *cmd_pos = strstr(cmd_buf, APPEND);
406         if (!cmd_pos)
407                 cmd_pos = strstr(cmd_buf, INSERT);
408
409         return cmd_pos;
410 }
411
412 static bool is_rule_present(const char *cmd_buf)
413 {
414         size_t buf_len;
415         char *exec_buf;
416         char *cmd_pos = get_cmd_pos(cmd_buf);
417         bool ret = false;
418         if (!cmd_pos)
419                 return false;
420
421         buf_len = strlen(cmd_buf) + 1;
422         exec_buf = (char *)malloc(buf_len);
423         if (!exec_buf)
424                 return false;
425
426         strncpy(exec_buf, cmd_buf, buf_len);
427         strncpy(exec_buf + (cmd_pos - cmd_buf), IPTABLES_CHECK,
428                 sizeof(IPTABLES_CHECK) - 1);
429
430         STC_LOGD("check rule %s", exec_buf);
431
432         ret = system(exec_buf) == 0;
433         free(exec_buf);
434         return ret;
435 }
436
437 stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
438 {
439         const size_t args_number = get_args_number(cmd_buf);
440         *cmd_pid = 0;
441
442         ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
443
444         pid_t pid = fork();
445
446         if (pid == 0) {
447                 char *cmd;
448                 unsigned int i;
449                 char *args[args_number + 2];
450                 int ret;
451                 char *save_ptr = NULL;
452
453                 STC_LOGD("executing iptables cmd %s in forked process",
454                          cmd_buf);
455
456                 if (is_rule_present(cmd_buf)) {
457                         STC_LOGD("Rule %s already present", cmd_buf);
458                         exit(0);
459                 }
460
461                 args[0] = "iptables";
462                 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
463                 if (cmd == NULL) {
464                         STC_LOGE("no arguments");
465                         exit(-EINVAL);
466                 }
467
468                 for (i = 1; i <= args_number; ++i)
469                         args[i] = strtok_r(NULL, " ", &save_ptr);
470
471                 args[i] = NULL;
472
473                 ret = execv(cmd, args);
474                 if (ret) {
475                         char buf[BUF_SIZE_FOR_ERR] = { 0 };
476                         STC_LOGE("Can't execute %s: %s",
477                                  cmd_buf, strerror_r(errno, buf,
478                                                      BUF_SIZE_FOR_ERR));
479                 }
480                 exit(ret);
481         }
482
483         *cmd_pid = pid;
484         return STC_ERROR_NONE;
485 }
486
487 stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
488 {
489         const size_t args_number = get_args_number(cmd_buf);
490         *cmd_pid = 0;
491
492         ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
493
494         pid_t pid = fork();
495
496         if (pid == 0) {
497                 char *cmd;
498                 unsigned int i;
499                 char *args[args_number + 2];
500                 int ret;
501                 char *save_ptr = NULL;
502
503                 STC_LOGD("executing ip6tables cmd %s in forked process",
504                          cmd_buf);
505
506                 if (is_rule_present(cmd_buf)) {
507                         STC_LOGD("Rule %s already present", cmd_buf);
508                         exit(0);
509                 }
510
511                 args[0] = "ip6tables";
512                 cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
513                 if (cmd == NULL) {
514                         STC_LOGE("no arguments");
515                         exit(-EINVAL);
516                 }
517
518                 for (i = 1; i <= args_number; ++i)
519                         args[i] = strtok_r(NULL, " ", &save_ptr);
520
521                 args[i] = NULL;
522
523                 ret = execv(cmd, args);
524                 if (ret) {
525                         char buf[BUF_SIZE_FOR_ERR] = { 0 };
526                         STC_LOGE("Can't execute %s: %s",
527                                  cmd_buf, strerror_r(errno, buf,
528                                                      BUF_SIZE_FOR_ERR));
529                 }
530                 exit(ret);
531         }
532
533         *cmd_pid = pid;
534         return STC_ERROR_NONE;
535 }
536
537 static char *choose_iftype_name(nfacct_rule_s *rule)
538 {
539         return strlen(rule->ifname) != 0 ? rule->ifname :
540                 get_iftype_name(rule->iftype);
541 }
542
543 static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd,
544                                   const char *chain, const char *nfacct,
545                                   const char *jump, char *iftype_name,
546                                   pid_t *pid, nfacct_rule_iptype iptype)
547 {
548         char block_buf[MAX_PATH_LENGTH];
549         int ret;
550         const char *iptables_type = IPTABLES;
551
552         ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
553                          "Invalid network interface name argument");
554
555         if (iptype == NFACCT_TYPE_IPV6)
556                 iptables_type = IP6TABLES;
557
558         ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
559                        cmd, chain, iftype_name, nfacct, jump);
560         ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
561                          "Not enough buffer");
562
563         if (iptype == NFACCT_TYPE_IPV6)
564                 exec_ip6tables_cmd(block_buf, pid);
565         else
566                 exec_iptables_cmd(block_buf, pid);
567
568         wait_for_rule_cmd(*pid);
569
570         return STC_ERROR_NONE;
571 }
572
573 static stc_error_e exec_app_cmd(const char *pattern, const char *cmd,
574                                 const char *nfacct, const char *jump,
575                                 const uint32_t classid, char *iftype_name,
576                                 pid_t *pid, nfacct_rule_iptype iptype)
577 {
578         char block_buf[MAX_PATH_LENGTH];
579         int ret;
580         const char *iptables_type = IPTABLES;
581
582         ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
583                          "Invalid network interface name argument");
584
585         if (iptype == NFACCT_TYPE_IPV6)
586                 iptables_type = IP6TABLES;
587
588         ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
589                        cmd, iftype_name, classid, nfacct, jump);
590         ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
591                          "Not enough buffer");
592
593         if (iptype == NFACCT_TYPE_IPV6)
594                 exec_ip6tables_cmd(block_buf, pid);
595         else
596                 exec_iptables_cmd(block_buf, pid);
597
598         wait_for_rule_cmd(*pid);
599
600         return STC_ERROR_NONE;
601 }
602
603 static char *get_iptables_cmd(const nfacct_rule_action action)
604 {
605         if (action == NFACCT_ACTION_APPEND)
606                 return APPEND;
607         else if (action == NFACCT_ACTION_DELETE)
608                 return DELETE;
609         else if (action == NFACCT_ACTION_INSERT)
610                 return INSERT;
611
612         return "";
613 }
614
615 static char *get_iptables_chain(const nfacct_rule_direction iotype)
616 {
617         if (iotype == NFACCT_COUNTER_IN)
618                 return IN_RULE;
619         else if (iotype == NFACCT_COUNTER_OUT)
620                 return OUT_RULE;
621
622         return "";
623 }
624
625 static char *get_iptables_jump(const nfacct_rule_jump jump)
626 {
627         if (jump == NFACCT_JUMP_ACCEPT)
628                 return ACCEPT_RULE;
629         else if (jump == NFACCT_JUMP_REJECT)
630                 return REJECT_RULE;
631
632         return "";
633 }
634
635 static stc_error_e produce_app_rule(nfacct_rule_s *rule)
636 {
637         if (rule == NULL)
638                 return STC_ERROR_INVALID_PARAMETER;
639
640         char *set_cmd = get_iptables_cmd(rule->action);
641         char *jump_cmd = get_iptables_jump(rule->jump);
642         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
643                 3*MAX_DEC_SIZE(int) + 4];
644         stc_error_e ret = STC_ERROR_NONE;
645         pid_t pid = 0;
646
647         /* income part */
648         if (rule->iotype & NFACCT_COUNTER_IN) {
649                 rule->quota = rule->rcv_limit;
650                 rule->iotype = NFACCT_COUNTER_IN;
651                 generate_counter_name(rule);
652
653                 /* to support quated counter we need nfacct,
654                  *      don't use it in case of just block without a limit
655                  *      iow, send_limit = 0 and rcv_limit 0 */
656                 if (rule->action != NFACCT_ACTION_DELETE) {
657                         ret = nfacct_send_del(rule);
658                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
659                                          "can't del quota counter");
660
661                         ret = nfacct_send_new(rule);
662                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
663                                          "can't set nfacct counter");
664                         keep_counter(rule);
665                 }
666
667                 /* we have a counter, let's key in a rule, drop in case of
668                  *  send_limit/rcv_limit */
669                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
670                                rule->name);
671                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
672                                  STC_ERROR_FAIL, "Not enought buffer");
673
674                 ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
675                                    rule->classid, choose_iftype_name(rule),
676                                    &pid, rule->iptype);
677                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
678                                  "Can't set conditional block for ingress"
679                                  " traffic, for classid %u, cmd %s, j %s",
680                                  rule->classid, set_cmd, jump_cmd);
681
682                 /* remove in any case */
683                 if (rule->action == NFACCT_ACTION_DELETE) {
684                         /* TODO here and everywhere should be not just a del,
685                          *      here should be get counted value and than
686                          *      set new counter with that value, but it's minor issue,
687                          *      due it's not clear when actual counters was stored,
688                          *      and based on which value settings made such decition */
689                         rule->iptables_rule = nfacct_send_del;
690                         set_finalize_flag(rule);
691                         nfacct_send_get(rule);
692                         ret = nfacct_send_del(rule);
693                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
694                                          "can't del quota counter");
695                 }
696         }
697
698         if (rule->iotype & NFACCT_COUNTER_OUT) {
699                 /* outcome part */
700                 rule->iotype = NFACCT_COUNTER_OUT;
701                 rule->quota = rule->send_limit;
702                 generate_counter_name(rule);
703                 if (rule->action != NFACCT_ACTION_DELETE) {
704                         ret = nfacct_send_del(rule);
705                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
706                                          "can't del quota counter");
707
708                         ret = nfacct_send_new(rule);
709                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
710                                          "can't set quota counter");
711                         keep_counter(rule);
712                 }
713
714                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
715                                rule->name);
716                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
717                                  STC_ERROR_FAIL, "Not enought buffer");
718
719                 ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
720                                    rule->classid, choose_iftype_name(rule),
721                                    &pid, rule->iptype);
722                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
723                                  "Can't set conditional block for engress"
724                                  " traffic, for classid %u, cmd %s, j %s",
725                                  rule->classid, set_cmd, jump_cmd);
726                 if (rule->action == NFACCT_ACTION_DELETE) {
727                         rule->iptables_rule = nfacct_send_del;
728                         /* not effective, it's better to replace
729                          * set_finalize_flag by set_property,
730                          * due keep_counter it necessary only for
731                          * setting iptables_rule */
732                         set_finalize_flag(rule);
733                         nfacct_send_get(rule);
734                         ret = nfacct_send_del(rule);
735                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
736                                          "can't del quota counter");
737                 }
738         }
739         return STC_ERROR_NONE;
740 }
741
742 static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
743 {
744         if (rule == NULL)
745                 return STC_ERROR_INVALID_PARAMETER;
746
747         char *set_cmd = get_iptables_cmd(rule->action);
748         char *jump_cmd = get_iptables_jump(rule->jump);
749         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
750                 3*MAX_DEC_SIZE(int) + 4];
751         stc_error_e ret;
752         pid_t pid = 0;
753
754         if (rule->iotype & NFACCT_COUNTER_IN) {
755                 /* income part */
756                 rule->iotype = NFACCT_COUNTER_IN;
757                 rule->quota = rule->rcv_limit;
758                 generate_counter_name(rule);
759
760                 if (rule->action != NFACCT_ACTION_DELETE) {
761                         /* send delete comman in case of creation,
762                          * because nfacct doesn't reset value for nfacct quota
763                          * in case of quota existing */
764                         ret = nfacct_send_del(rule);
765                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
766                                          "can't del quota counter");
767
768                         ret = nfacct_send_new(rule);
769                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
770                                          "can't set quota counter");
771                         keep_counter(rule);
772                 }
773
774                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
775                                NFACCT_NAME_MOD, rule->name);
776                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
777                                  STC_ERROR_FAIL, "Not enought buffer");
778
779                 ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
780                                      get_iptables_chain(rule->iotype),
781                                      nfacct_buf, jump_cmd,
782                                      choose_iftype_name(rule), &pid,
783                                      rule->iptype);
784                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
785                                  "Can't set conditional block for ingress"
786                                  " traffic, for iftype %d, cmd %s, j %s",
787                                  rule->iftype, set_cmd, jump_cmd);
788
789                 /* for tethering */
790                 if (rule->intend == NFACCT_WARN ||
791                     rule->intend == NFACCT_BLOCK) {
792                         /* RULE_IFACE_OUT is not a misprint here */
793                         ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
794                                              FORWARD_RULE, nfacct_buf, jump_cmd,
795                                              choose_iftype_name(rule), &pid,
796                                              rule->iptype);
797                         ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
798                                          "Can't set forward rule for ingress "
799                                          "traffic, for iftype %d, cmd %s, j %s",
800                                          rule->iftype, set_cmd, jump_cmd);
801                 }
802                 /* tethering */
803
804                 if (rule->action == NFACCT_ACTION_DELETE) {
805                         rule->iptables_rule = nfacct_send_del;
806                         set_finalize_flag(rule);
807                         nfacct_send_get(rule);
808                         ret = nfacct_send_del(rule);
809                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
810                                          "can't del quota counter");
811                 }
812         }
813
814         if (rule->iotype & NFACCT_COUNTER_OUT) {
815                 /* outcome part */
816                 rule->iotype = NFACCT_COUNTER_OUT;
817                 rule->quota = rule->send_limit;
818                 generate_counter_name(rule);
819
820                 if (rule->action != NFACCT_ACTION_DELETE) {
821                         /* send delete comman in case of creation,
822                          * because nfacct doesn't reset value for nfacct quota
823                          * in case of quota existing */
824                         ret = nfacct_send_del(rule);
825                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
826                                          "can't del quota counter");
827
828                         ret = nfacct_send_new(rule);
829                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
830                                          "can't set quota counter");
831                         keep_counter(rule);
832                 }
833
834                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
835                                NFACCT_NAME_MOD, rule->name);
836                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
837                                  STC_ERROR_FAIL, "Not enough buffer");
838
839                 ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
840                                      nfacct_buf, jump_cmd,
841                                      choose_iftype_name(rule), &pid,
842                                      rule->iptype);
843                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
844                                  "Can't set conditional block for "
845                                  "engress traffic, for iftype %d, cmd %s, j %s",
846                                  rule->iftype, set_cmd, jump_cmd);
847                 /* for tethering  */
848                 if (rule->intend == NFACCT_WARN ||
849                     rule->intend == NFACCT_BLOCK) {
850                         ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
851                                              FORWARD_RULE, nfacct_buf, jump_cmd,
852                                              choose_iftype_name(rule), &pid,
853                                              rule->iptype);
854                         ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
855                                          "Can't set forward rule for engress "
856                                          "traffic, for iftype %d, cmd %s, j %s",
857                                          rule->iftype, set_cmd, jump_cmd);
858                 }
859                 /* tethering  */
860
861                 if (rule->action == NFACCT_ACTION_DELETE) {
862                         rule->iptables_rule = nfacct_send_del;
863                         set_finalize_flag(rule);
864                         nfacct_send_get(rule);
865                         ret = nfacct_send_del(rule);
866                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
867                                          "can't del quota counter");
868                 }
869         }
870         return STC_ERROR_NONE;
871 }
872
873 stc_error_e produce_net_rule(nfacct_rule_s *rule)
874 {
875         stc_error_e ret = STC_ERROR_NONE;
876
877         if (rule == NULL)
878                 return STC_ERROR_INVALID_PARAMETER;
879
880         if (rule->action == NFACCT_ACTION_APPEND &&
881             rule->intend == NFACCT_WARN &&
882             !rule->send_limit && !rule->rcv_limit)
883                 return STC_ERROR_NONE;
884
885         if (rule->classid != STC_ALL_APP_CLASSID &&
886             rule->classid != STC_TETHERING_APP_CLASSID &&
887             rule->classid != STC_TOTAL_DATACALL_CLASSID &&
888             rule->classid != STC_TOTAL_WIFI_CLASSID &&
889             rule->classid != STC_TOTAL_BLUETOOTH_CLASSID &&
890             rule->classid != STC_TOTAL_IPV4_CLASSID &&
891             rule->classid != STC_TOTAL_IPV6_CLASSID)
892                 ret = produce_app_rule(rule);
893         else
894                 ret = produce_iface_rule(rule);
895
896         return ret;
897 }
898
899 void generate_counter_name(nfacct_rule_s *counter)
900 {
901         char warn_symbol = 'c';
902         if (!strlen(counter->ifname)) {
903                 char *iftype_name = get_iftype_name(counter->iftype);
904                 /* trace counter name, maybe name was already generated */
905                 ret_msg_if(iftype_name == NULL,
906                            "Can't get interface name for counter %s, iftype %d)!",
907                            counter->name, counter->iftype);
908                 STRING_SAVE_COPY(counter->ifname, iftype_name);
909         }
910
911         if (counter->intend  == NFACCT_WARN)
912                 warn_symbol = 'w';
913         else if (counter->intend  == NFACCT_BLOCK)
914                 warn_symbol = 'r';
915         snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
916                  warn_symbol, counter->iotype, counter->iftype,
917                  counter->classid, counter->ifname);
918 }
919