Merge "Added firewall feature" into tizen
[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 #include "helper-iptables.h"
30
31 #include "configure_stub.h"
32
33 #define IPTABLES "/usr/sbin/iptables"
34 #define IP6TABLES "/usr/sbin/ip6tables"
35 #define IPTABLES_CHECK "-C"
36 #define APPEND "-A"
37 #define DELETE "-D"
38 #define INSERT "-I"
39
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"
46
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"
50
51 /* iptables -w [I/A/D] [OUTPUT/FORWARD/INPUT] -o/-i iface -m nfacct --nfacct-name name -j ACCEPT/REJECT */
52
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"
55
56 #define NFNL_SUBSYS_ACCT                7
57 #define BUF_SIZE_FOR_ERR 100
58
59 static void prepare_netlink_msg(struct genl *req, int type, int flag)
60 {
61         int seq = time(NULL);
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;
67 }
68
69 static void add_value_attr(struct genl *req, const void *data, int len,
70                            int type)
71 {
72         int payload;
73         /* get tail */
74         struct nlattr *na = (struct nlattr *)((char *)req +
75                                               NLMSG_ALIGN(req->n.nlmsg_len));
76
77         na->nla_type = type;
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);
82 }
83
84 /*
85  * following 2 function should be used in combination.
86  * start_nest_attr returns nlattr structure, which should be completed by
87  * end_nest_attr,
88  * before these invocations any number of netlink arguments could be inserted
89  * */
90 static struct nlattr *start_nest_attr(struct genl *req, uint16_t type)
91 {
92         struct nlattr *start = (struct nlattr *)((char *)req +
93                                                  NLMSG_ALIGN(req->n.nlmsg_len));
94
95         start->nla_type = NLA_F_NESTED | type;
96         req->n.nlmsg_len += NLMSG_ALIGN(sizeof(struct nlattr));
97         return start;
98 }
99
100 static void end_nest_attr(struct genl *req, struct nlattr *start)
101 {
102         start->nla_len = (__u16)((char *)req +
103                                  NLMSG_ALIGN(req->n.nlmsg_len) - (char *)start);
104 }
105
106 static void add_string_attr(struct genl *req, const char *str, int type)
107 {
108         add_value_attr(req, str, strlen(str) + 1, type);
109 }
110
111 static void add_uint64_attr(struct genl *req, const uint64_t v, int type)
112 {
113         add_value_attr(req, &v, sizeof(v), type);
114 }
115
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)
118 {
119         add_value_attr(req, &v, sizeof(v), type);
120 }
121
122 static stc_error_e send_nfacct_request(int sock, struct genl *req)
123 {
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);
129
130         return STC_ERROR_NONE;
131 }
132
133 static stc_error_e nfacct_send_new(nfacct_rule_s *counter)
134 {
135         int ret = STC_ERROR_NONE;
136         struct genl *req = MALLOC0(struct genl, 1);
137         if (req == NULL) {
138                 STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
139                 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
140         }
141
142         prepare_netlink_msg(req, NFNL_MSG_ACCT_NEW, NLM_F_CREATE | NLM_F_ACK);
143         add_string_attr(req, counter->name, NFACCT_NAME);
144
145         if (STC_DEBUG_LOG)
146                 STC_LOGD("counter name %s", counter->name); //LCOV_EXCL_LINE
147
148         /* padding */
149         add_uint64_attr(req, 0, NFACCT_PKTS);
150         add_uint64_attr(req, 0, NFACCT_BYTES);
151         //LCOV_EXCL_START
152         if (counter->quota) {
153                 STC_LOGD("quota bytes %"PRId64, counter->quota);
154
155                 add_uint32_attr(req, htobe32(NFACCT_F_QUOTA_BYTES),
156                                 NFACCT_FLAGS);
157                 add_uint64_attr(req, htobe64(counter->quota), NFACCT_QUOTA);
158         }
159         //LCOV_EXCL_STOP
160
161         ret = send_nfacct_request(counter->carg->sock, req);
162         FREE(req);
163         return ret;
164 }
165
166 stc_error_e nfacct_send_del(nfacct_rule_s *counter)
167 {
168         int ret = STC_ERROR_NONE;
169         struct genl *req = MALLOC0(struct genl, 1);
170         if (req == NULL) {
171                 STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
172                 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
173         }
174
175         if (STC_DEBUG_LOG)
176                 STC_LOGD("send remove request for %s", counter->name); //LCOV_EXCL_LINE
177
178         prepare_netlink_msg(req, NFNL_MSG_ACCT_DEL, NLM_F_ACK);
179         add_string_attr(req, counter->name, NFACCT_NAME);
180
181         ret = send_nfacct_request(counter->carg->sock, req);
182         FREE(req);
183         return ret;
184 }
185 #define NFACCT_F_QUOTAS (NFACCT_F_QUOTA_BYTES | NFACCT_F_QUOTA_PKTS)
186
187 static stc_error_e internal_nfacct_send_get(struct counter_arg *carg,
188                                             enum nfnl_acct_msg_types get_type,
189                                             const char *name,
190                                             int mask, int filter)
191 {
192         int ret = STC_ERROR_NONE;
193         struct nlattr *na;
194         int flag = !name ? NLM_F_DUMP : 0;
195         struct genl *req = MALLOC0(struct genl, 1);
196         if (req == NULL) {
197                 STC_LOGE("Failed allocate memory to genl request message"); //LCOV_EXCL_LINE
198                 return STC_ERROR_OUT_OF_MEMORY; //LCOV_EXCL_LINE
199         }
200
201         prepare_netlink_msg(req, get_type, flag);
202         /* due we don't get counter with quota any where else,
203          * here we will request just counters by default */
204         if (name)
205                 add_string_attr(req, name, NFACCT_NAME);
206
207         na = start_nest_attr(req, NFACCT_FILTER);
208         add_uint32_attr(req, htonl(mask), NFACCT_FILTER_ATTR_MASK);
209         add_uint32_attr(req, htonl(filter), NFACCT_FILTER_ATTR_VALUE);
210         end_nest_attr(req, na);
211
212         ret = send_nfacct_request(carg->sock, req);
213         FREE(req);
214         return ret;
215 }
216
217 stc_error_e nfacct_send_get_counters(struct counter_arg *carg, const char *name)
218 {
219         /* get and reset countes value */
220         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, name,
221                                         NFACCT_F_QUOTAS, 0);
222 }
223
224 stc_error_e nfacct_send_get_quotas(struct counter_arg *carg, const char *name)
225 {
226         /* just get counters */
227         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET, name,
228                                         NFACCT_F_QUOTA_BYTES,
229                                         NFACCT_F_QUOTA_BYTES);
230 }
231
232 stc_error_e nfacct_send_get_all(struct counter_arg *carg)
233 {
234         /* get and reset everything, used when quiting */
235         return internal_nfacct_send_get(carg, NFNL_MSG_ACCT_GET_CTRZERO, NULL,
236                                         0, 0);
237 }
238
239 stc_error_e nfacct_send_get(nfacct_rule_s *rule)
240 {
241         if (rule->intend == NFACCT_BLOCK || rule->intend == NFACCT_WARN)
242                 return nfacct_send_get_quotas(rule->carg, rule->name);
243         else if (rule->intend == NFACCT_COUNTER)
244                 return nfacct_send_get_counters(rule->carg, rule->name);
245
246         return STC_ERROR_INVALID_PARAMETER;
247 }
248
249 static nfacct_rule_direction convert_to_iotype(int type)
250 {
251         return (type < NFACCT_COUNTER_LAST_ELEM &&
252                 type > NFACCT_COUNTER_UNKNOWN) ? type : NFACCT_COUNTER_UNKNOWN;
253 }
254
255 static stc_iface_type_e convert_to_iftype(int type)
256 {
257         return (type < STC_IFACE_LAST_ELEM &&
258                 type > STC_IFACE_UNKNOWN) ? type : STC_IFACE_UNKNOWN;
259 }
260
261 bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt)
262 {
263         char *iftype_part;
264         char *classid_part;
265         char *io_part;
266         char *ifname_part;
267         char *save_ptr = NULL;
268         char name[NFACCT_NAME_MAX] = {0}; /* parse buffer to avoid cnt_name modification */
269
270         strncpy(name, cnt_name, sizeof(name) - 1);
271
272         switch (name[0]) {
273         case 'c':
274                 cnt->intend  = NFACCT_COUNTER;
275                 break;
276         case 'w':
277                 cnt->intend  = NFACCT_WARN;
278                 break;
279         case 'r':
280                 cnt->intend  = NFACCT_BLOCK;
281                 break;
282         case 'a':
283                 cnt->intend  = NFACCT_ALLOW;
284                 break;
285         case 't':
286                 cnt->intend  = NFACCT_TETH_COUNTER; //LCOV_EXCL_LINE
287                 break; //LCOV_EXCL_LINE
288         default:
289                 return false;
290         }
291
292         STRING_SAVE_COPY(cnt->name, cnt_name);
293
294         //LCOV_EXCL_START
295         if (cnt->intend == NFACCT_TETH_COUNTER) {
296                 char ifname_buf[MAX_IFACE_LENGTH];
297                 int ifname_len;
298                 stc_iface_type_e iface;
299                 /* tbnep+:seth_w0; means comes by bt go away by mobile interface,
300                  * it's outgoing traffic, due all tethering is mobile databased */
301                 iftype_part = strchr(name, ':');
302                 ret_value_msg_if(iftype_part == NULL,
303                                  false, "Invalid format of the tethering counter %s", name);
304                 ifname_len = iftype_part - name - 1;
305                 strncpy(ifname_buf, name + 1, ifname_len); /* skip first t */
306                 ifname_buf[ifname_len] = '\0';
307                 iface = get_iftype_by_name(ifname_buf);
308                 /* check first part is it datacall */
309                 if (iface == STC_IFACE_DATACALL) {
310                         strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
311                         cnt->iotype = NFACCT_COUNTER_IN;
312                 } else {
313                         /* +1, due : symbol and till the end of cnt_name */
314                         strncpy(ifname_buf, iftype_part + 1, MAX_IFACE_LENGTH - 1);
315                         iface = get_iftype_by_name(ifname_buf);
316                         if (iface == STC_IFACE_DATACALL) {
317                                 cnt->iotype = NFACCT_COUNTER_OUT;
318                                 strncpy(cnt->ifname, ifname_buf, MAX_IFACE_LENGTH - 1);
319                         }
320                 }
321
322                 if (cnt->iotype == NFACCT_COUNTER_UNKNOWN) {
323                         STC_LOGE("can't determine tethering direction %s", name);
324                         return false;
325                 }
326                 cnt->iftype = STC_IFACE_DATACALL;
327                 cnt->classid = STC_TETHERING_APP_CLASSID;
328                 return true;
329         }
330         //LCOV_EXCL_STOP
331
332         io_part = strtok_r(name, "_", &save_ptr);
333         if (io_part != NULL)
334                 cnt->iotype = convert_to_iotype(atoi(io_part + 1));
335         else
336                 return false;
337
338         iftype_part = strtok_r(NULL, "_", &save_ptr);
339         if (iftype_part != NULL)
340                 cnt->iftype = convert_to_iftype(atoi(iftype_part));
341         else
342                 return false;
343
344         classid_part = strtok_r(NULL, "_", &save_ptr);
345         if (classid_part != NULL)
346                 cnt->classid = atoi(classid_part);
347         else {
348                 cnt->classid = STC_ALL_APP_CLASSID;
349                 return cnt->intend == NFACCT_BLOCK ? true : false;
350         }
351
352         ifname_part = strtok_r(NULL, "\0", &save_ptr);
353         if (ifname_part != NULL)
354                 STRING_SAVE_COPY(cnt->ifname, ifname_part);
355         else
356                 return false;
357
358         return true;
359 }
360
361 static void _process_answer(struct netlink_serialization_params *params)
362 {
363         struct rtattr *na;
364         struct rtattr *attr_list[__NFACCT_MAX] = {0};
365         struct counter_arg *carg = params->carg;
366         struct genl *ans = params->ans;;
367         struct nlmsghdr *nlhdr = &ans->n;
368         int len = GENLMSG_PAYLOAD(nlhdr);
369         int ans_len = carg->ans_len;
370
371         if (len == 0)
372                 return;
373
374         /* parse reply message */
375         na = (struct rtattr *)GENLMSG_DATA(ans);
376
377         while (NLMSG_OK(nlhdr, ans_len)) {
378                 fill_attribute_list(attr_list, NFACCT_MAX,
379                                     na, len);
380                 if (!attr_list[NFACCT_NAME] ||
381                     !attr_list[NFACCT_BYTES])
382                         goto next;
383                 params->eval_attr(attr_list, carg);
384
385 next:
386                 nlhdr = NLMSG_NEXT(nlhdr, ans_len);
387                 if (ans_len < 0)
388                         break;
389                 na = (struct rtattr *)GENLMSG_DATA(nlhdr);
390         }
391
392         if (params->post_eval_attr)
393                 params->post_eval_attr(carg);
394 }
395
396 netlink_serialization_command *
397 netlink_create_command(struct netlink_serialization_params *params)
398 {
399         static netlink_serialization_command command = {0,};
400         command.deserialize_answer = _process_answer;
401         command.params = *params;
402         return &command;
403 }
404
405 static char *get_iptables_cmd(const nfacct_rule_action action)
406 {
407         if (action == NFACCT_ACTION_APPEND)
408                 return APPEND;
409         else if (action == NFACCT_ACTION_DELETE)
410                 return DELETE;
411         else if (action == NFACCT_ACTION_INSERT)
412                 return INSERT;
413
414         return "";
415 }
416
417 static char *get_iptables_chain(const nfacct_rule_direction iotype)
418 {
419         if (iotype == NFACCT_COUNTER_IN)
420                 return STC_IN_CHAIN;
421         else if (iotype == NFACCT_COUNTER_OUT)
422                 return STC_OUT_CHAIN;
423         else if (iotype == NFACCT_COUNTER_FORWARD) //LCOV_EXCL_LINE
424                 return STC_FRWD_CHAIN; //LCOV_EXCL_LINE
425
426         return "";
427 }
428
429 static char *get_iptables_jump(const nfacct_rule_jump jump)
430 {
431         if (jump == NFACCT_JUMP_ACCEPT)
432                 return ACCEPT_RULE;
433         else if (jump == NFACCT_JUMP_REJECT)
434                 return REJECT_RULE;
435
436         return "";
437 }
438
439 /*
440 static char *choose_iftype_name(nfacct_rule_s *rule)
441 {
442         return strlen(rule->ifname) != 0 ? rule->ifname :
443                 get_iftype_name(rule->iftype);
444 }
445 */
446
447 static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
448 {
449         stc_error_e ret = STC_ERROR_NONE;
450         iptables_ip_type_e iptype;
451         iptables_rule_s iptables_rule;
452         memset(&iptables_rule, 0, sizeof(iptables_rule_s));
453
454         iptables_rule.nfacct_name = g_strdup(rule->name);
455         iptables_rule.ifname = g_strdup(rule->ifname);
456         iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
457         iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype));
458         iptables_rule.classid = rule->classid;
459         iptables_rule.direction = (rule->iotype & NFACCT_COUNTER_IN) ?
460                                         IPTABLES_DIRECTION_IN : IPTABLES_DIRECTION_OUT;
461         iptype = (iptables_ip_type_e)rule->iptype;
462
463         if (rule->action == NFACCT_ACTION_DELETE) {
464                 /* delete interface rule */
465                 ret = iptables_remove(&iptables_rule, iptype);
466         } else {
467                 /* add interface rule */
468                 ret = iptables_add(&iptables_rule, iptype);
469         }
470
471         g_free(iptables_rule.nfacct_name);
472         g_free(iptables_rule.ifname);
473         g_free(iptables_rule.target);
474         g_free(iptables_rule.chain);
475
476         return ret;
477 }
478
479 static stc_error_e produce_app_rule(nfacct_rule_s *rule)
480 {
481         if (rule == NULL)
482                 return STC_ERROR_INVALID_PARAMETER;
483
484         char *set_cmd = get_iptables_cmd(rule->action);
485         char *jump_cmd = get_iptables_jump(rule->jump);
486         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
487                 3*MAX_DEC_SIZE(int) + 4];
488         stc_error_e ret = STC_ERROR_NONE;
489
490         /* income part */
491         if (rule->iotype & NFACCT_COUNTER_IN) {
492                 rule->quota = rule->rcv_limit;
493                 rule->iotype = NFACCT_COUNTER_IN;
494                 generate_counter_name(rule);
495
496                 /* to support quated counter we need nfacct,
497                  *      don't use it in case of just block without a limit
498                  *      iow, send_limit = 0 and rcv_limit 0 */
499                 if (rule->action != NFACCT_ACTION_DELETE) {
500                         ret = nfacct_send_del(rule);
501                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
502                                          "can't del quota counter");
503
504                         ret = nfacct_send_new(rule);
505                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
506                                          "can't set nfacct counter");
507                         keep_counter(rule);
508                 }
509
510                 /* we have a counter, let's key in a rule, drop in case of
511                  *  send_limit/rcv_limit */
512                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
513                                rule->name);
514                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
515                                  STC_ERROR_FAIL, "Not enought buffer");
516
517                 ret = exec_iptables_cmd(rule);
518                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
519                                  "Can't set conditional block for ingress"
520                                  " traffic, for classid %u, cmd %s, j %s",
521                                  rule->classid, set_cmd, jump_cmd);
522
523                 /* remove in any case */
524                 if (rule->action == NFACCT_ACTION_DELETE) {
525                         /* TODO here and everywhere should be not just a del,
526                          *      here should be get counted value and than
527                          *      set new counter with that value, but it's minor issue,
528                          *      due it's not clear when actual counters was stored,
529                          *      and based on which value settings made such decition */
530                         rule->iptables_rule = nfacct_send_del;
531                         set_finalize_flag(rule);
532                         nfacct_send_get(rule);
533                         ret = nfacct_send_del(rule);
534                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
535                                          "can't del quota counter");
536                 }
537         }
538
539         if (rule->iotype & NFACCT_COUNTER_OUT) {
540                 /* outcome part */
541                 rule->iotype = NFACCT_COUNTER_OUT;
542                 rule->quota = rule->send_limit;
543                 generate_counter_name(rule);
544                 if (rule->action != NFACCT_ACTION_DELETE) {
545                         ret = nfacct_send_del(rule);
546                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
547                                          "can't del quota counter");
548
549                         ret = nfacct_send_new(rule);
550                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
551                                          "can't set quota counter");
552                         keep_counter(rule);
553                 }
554
555                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf), NFACCT_NAME_MOD,
556                                rule->name);
557                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
558                                  STC_ERROR_FAIL, "Not enought buffer");
559
560                 ret = exec_iptables_cmd(rule);
561                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
562                                  "Can't set conditional block for engress"
563                                  " traffic, for classid %u, cmd %s, j %s",
564                                  rule->classid, set_cmd, jump_cmd);
565
566                 if (rule->action == NFACCT_ACTION_DELETE) {
567                         rule->iptables_rule = nfacct_send_del;
568                         /* not effective, it's better to replace
569                          * set_finalize_flag by set_property,
570                          * due keep_counter it necessary only for
571                          * setting iptables_rule */
572                         set_finalize_flag(rule);
573                         nfacct_send_get(rule);
574                         ret = nfacct_send_del(rule);
575                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
576                                          "can't del quota counter");
577                 }
578         }
579         return STC_ERROR_NONE;
580 }
581
582 static stc_error_e produce_iface_rule(nfacct_rule_s *rule)
583 {
584         if (rule == NULL)
585                 return STC_ERROR_INVALID_PARAMETER;
586
587         char *set_cmd = get_iptables_cmd(rule->action);
588         char *jump_cmd = get_iptables_jump(rule->jump);
589         char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
590                 3*MAX_DEC_SIZE(int) + 4];
591         uint32_t classid = rule->classid;
592         stc_error_e ret;
593
594         if (rule->iotype & NFACCT_COUNTER_IN) {
595                 /* income part */
596                 rule->iotype = NFACCT_COUNTER_IN;
597                 rule->quota = rule->rcv_limit;
598                 generate_counter_name(rule);
599
600                 if (rule->action != NFACCT_ACTION_DELETE) {
601                         /* send delete comman in case of creation,
602                          * because nfacct doesn't reset value for nfacct quota
603                          * in case of quota existing */
604                         ret = nfacct_send_del(rule);
605                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
606                                          "can't del quota counter");
607
608                         ret = nfacct_send_new(rule);
609                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
610                                          "can't set quota counter");
611                         keep_counter(rule);
612                 }
613
614                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
615                                NFACCT_NAME_MOD, rule->name);
616                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
617                                  STC_ERROR_FAIL, "Not enought buffer");
618
619                 classid = rule->classid;
620                 rule->classid = 0;
621
622                 ret = exec_iptables_cmd(rule);
623                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
624                                  "Can't set conditional block for ingress"
625                                  " traffic, for iftype %d, cmd %s, j %s",
626                                  rule->iftype, set_cmd, jump_cmd);
627
628                 //LCOV_EXCL_START
629                 /* for tethering */
630                 if (rule->intend == NFACCT_WARN ||
631                     rule->intend == NFACCT_BLOCK) {
632                         /* RULE_IFACE_OUT is not a misprint here */
633                         nfacct_rule_direction temp_iotype = rule->iotype;
634
635                         rule->iotype = NFACCT_COUNTER_FORWARD;
636                         ret = exec_iptables_cmd(rule);
637                         rule->iotype = temp_iotype;
638                         ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
639                                          "Can't set forward rule for ingress "
640                                          "traffic, for iftype %d, cmd %s, j %s",
641                                          rule->iftype, set_cmd, jump_cmd);
642                 }
643                 /* tethering */
644
645                 if (rule->action == NFACCT_ACTION_DELETE) {
646                         rule->iptables_rule = nfacct_send_del;
647                         set_finalize_flag(rule);
648                         nfacct_send_get(rule);
649                         ret = nfacct_send_del(rule);
650                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
651                                          "can't del quota counter");
652                 }
653                 //LCOV_EXCL_STOP
654         }
655
656         rule->classid = classid;
657
658         if (rule->iotype & NFACCT_COUNTER_OUT) {
659                 /* outcome part */
660                 rule->iotype = NFACCT_COUNTER_OUT;
661                 rule->quota = rule->send_limit;
662                 generate_counter_name(rule);
663
664                 if (rule->action != NFACCT_ACTION_DELETE) {
665                         /* send delete comman in case of creation,
666                          * because nfacct doesn't reset value for nfacct quota
667                          * in case of quota existing */
668                         ret = nfacct_send_del(rule);
669                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
670                                          "can't del quota counter");
671
672                         ret = nfacct_send_new(rule);
673                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
674                                          "can't set quota counter");
675                         keep_counter(rule);
676                 }
677
678                 ret = snprintf(nfacct_buf, sizeof(nfacct_buf),
679                                NFACCT_NAME_MOD, rule->name);
680                 ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
681                                  STC_ERROR_FAIL, "Not enough buffer");
682
683                 classid = rule->classid;
684                 rule->classid = 0;
685
686                 ret = exec_iptables_cmd(rule);
687                 ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
688                                  "Can't set conditional block for "
689                                  "engress traffic, for iftype %d, cmd %s, j %s",
690                                  rule->iftype, set_cmd, jump_cmd);
691
692                 //LCOV_EXCL_START
693                 /* for tethering  */
694                 if (rule->intend == NFACCT_WARN ||
695                     rule->intend == NFACCT_BLOCK) {
696                         nfacct_rule_direction temp_iotype = rule->iotype;
697
698                         rule->iotype = NFACCT_COUNTER_OUT;
699                         ret = exec_iptables_cmd(rule);
700                         rule->iotype = temp_iotype;
701                         ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
702                                          "Can't set forward rule for engress "
703                                          "traffic, for iftype %d, cmd %s, j %s",
704                                          rule->iftype, set_cmd, jump_cmd);
705                 }
706                 /* tethering  */
707
708                 if (rule->action == NFACCT_ACTION_DELETE) {
709                         rule->iptables_rule = nfacct_send_del;
710                         set_finalize_flag(rule);
711                         nfacct_send_get(rule);
712                         ret = nfacct_send_del(rule);
713                         ret_value_msg_if(ret != STC_ERROR_NONE, ret,
714                                          "can't del quota counter");
715                 }
716                 //LCOV_EXCL_STOP
717         }
718         return STC_ERROR_NONE;
719 }
720
721 stc_error_e produce_net_rule(nfacct_rule_s *rule)
722 {
723         stc_error_e ret = STC_ERROR_NONE;
724
725         if (rule == NULL)
726                 return STC_ERROR_INVALID_PARAMETER;
727
728         if (rule->action == NFACCT_ACTION_APPEND &&
729             rule->intend == NFACCT_WARN &&
730             !rule->send_limit && !rule->rcv_limit)
731                 return STC_ERROR_NONE;
732
733         if (rule->classid != STC_ALL_APP_CLASSID &&
734             rule->classid != STC_TETHERING_APP_CLASSID &&
735             rule->classid != STC_TOTAL_DATACALL_CLASSID &&
736             rule->classid != STC_TOTAL_WIFI_CLASSID &&
737             rule->classid != STC_TOTAL_BLUETOOTH_CLASSID &&
738             rule->classid != STC_TOTAL_IPV4_CLASSID &&
739             rule->classid != STC_TOTAL_IPV6_CLASSID)
740                 ret = produce_app_rule(rule);
741         else
742                 ret = produce_iface_rule(rule);
743
744         return ret;
745 }
746
747 void generate_counter_name(nfacct_rule_s *counter)
748 {
749         char warn_symbol = 'c';
750         if (!strlen(counter->ifname)) {
751                 char *iftype_name = get_iftype_name(counter->iftype);
752                 /* trace counter name, maybe name was already generated */
753                 ret_msg_if(iftype_name == NULL,
754                            "Can't get interface name for counter %s, iftype %d)!",
755                            counter->name, counter->iftype);
756                 STRING_SAVE_COPY(counter->ifname, iftype_name);
757         }
758
759         if (counter->intend  == NFACCT_WARN)
760                 warn_symbol = 'w';
761         else if (counter->intend  == NFACCT_BLOCK)
762                 warn_symbol = 'r';
763         else if (counter->intend  == NFACCT_ALLOW)
764                 warn_symbol = 'a';
765         snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s",
766                  warn_symbol, counter->iotype, counter->iftype,
767                  counter->classid, counter->ifname);
768 }
769