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