From a72b6122101219d7acd0ab83b7c74a90d3599596 Mon Sep 17 00:00:00 2001 From: Milind Murhekar Date: Wed, 29 Aug 2018 16:33:11 +0530 Subject: [PATCH] Add tethering client data limitation This change/feature adds the data limitaion restriction on each connected tethering clients based on its mac address, ip address and app id. Change-Id: I538450a68bb6e099d277bce0a6fe53a80d483332 Signed-off-by: Milind Murhekar --- include/stc-manager-plugin-tether.h | 5 +- packaging/stc-manager.spec | 2 +- plugin/tether/include/stc-plugin-tether.h | 21 +- plugin/tether/stc-plugin-tether.c | 80 ++++++- src/database/include/table-restrictions.h | 1 + src/helper/helper-iptables.c | 1 - src/helper/helper-nfacct-rule.c | 42 +++- src/helper/helper-nfacct-rule.h | 3 + src/monitor/include/stc-monitor.h | 5 +- src/monitor/stc-monitor.c | 380 +++++++++++++++++++++++++++--- src/stc-manager-plugin-tether.c | 66 ++++++ src/stc-restriction.c | 6 + 12 files changed, 550 insertions(+), 62 deletions(-) diff --git a/include/stc-manager-plugin-tether.h b/include/stc-manager-plugin-tether.h index bdee306..8fd874b 100644 --- a/include/stc-manager-plugin-tether.h +++ b/include/stc-manager-plugin-tether.h @@ -24,6 +24,7 @@ int stc_plugin_tether_init(void); int stc_plugin_tether_deinit(void); stc_error_e stc_plugin_tether_load(void); -stc_error_e stc_plugin_tether_status_changed(void); - +int stc_plugin_tether_get_station_ip(const char *mac, char **ipaddr); +int stc_plugin_tether_get_station_by_classid(const int classid, char **mac); +int stc_plugin_tether_set_station_classid(const char *mac, int classid); #endif /* __STC_MANAGER_PLUGIN_TETHER_H__ */ diff --git a/packaging/stc-manager.spec b/packaging/stc-manager.spec index b57a246..d84c351 100644 --- a/packaging/stc-manager.spec +++ b/packaging/stc-manager.spec @@ -1,6 +1,6 @@ Name: stc-manager Summary: STC(Smart Traffic Control) manager -Version: 0.0.75 +Version: 0.0.76 Release: 0 Group: Network & Connectivity/Other License: Apache-2.0 diff --git a/plugin/tether/include/stc-plugin-tether.h b/plugin/tether/include/stc-plugin-tether.h index b3d4439..f021516 100644 --- a/plugin/tether/include/stc-plugin-tether.h +++ b/plugin/tether/include/stc-plugin-tether.h @@ -18,29 +18,34 @@ #define __STC_PLUGIN_TETHER_H__ #include +#include #include "stc-error.h" #include "stc-manager.h" #define TETHERING_SERVICE_INTERFACE "org.tizen.tethering" #define SIGNAL_NAME_DHCP_STATUS "dhcp_status" -#define STATION_STR_INFO_LEN 54 +#define STATION_MAC_STR_LEN 18 #define STATION_STR_HOSTNAME_LEN 33 typedef struct { - gchar *station_id; - gchar name[STATION_STR_HOSTNAME_LEN + 1]; - gchar ip[STATION_STR_INFO_LEN + 1]; - gchar mac[STATION_STR_INFO_LEN + 1]; + gchar *station_id; /* Station unique ID (mac_hostname)*/ + int classid; /* cgroup net_cls Classid of station */ + gchar name[STATION_STR_HOSTNAME_LEN+1]; /* Station hostname */ + gchar ip[INET_ADDRSTRLEN+1]; /* Station IP address */ + gchar mac[STATION_MAC_STR_LEN+1]; /* Station MAC address */ } tether_sta_info_s; typedef struct { int (*init) (void); void (*deinit) (void); - int (*status_changed) (void); + int (*get_station_ip) (const char *mac, char *ip); + int (*get_station_by_classid) (const int classid, char *mac); + int (*set_station_classid) (const char *mac, int classid); } stc_plugin_tether_s; int tether_init(void); void tether_deinit(void); -stc_error_e tether_plugin_status_changed(void); - +stc_error_e tether_plugin_get_station_ip(const char *mac, char *ip); +stc_error_e tether_plugin_get_station_by_classid(const int classid, char *mac); +stc_error_e tether_plugin_set_station_classid(const char *mac, int classid); #endif /* __STC_PLUGIN_TETHER_H__ */ diff --git a/plugin/tether/stc-plugin-tether.c b/plugin/tether/stc-plugin-tether.c index 629abbf..2641509 100644 --- a/plugin/tether/stc-plugin-tether.c +++ b/plugin/tether/stc-plugin-tether.c @@ -31,13 +31,14 @@ static GDBusConnection *connection = NULL; static GCancellable *cancellable = NULL; static int g_mobileap_signal_sub_id = 0; -static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id, const char *ip) +static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id, + const char *mac) { int ret; stc_app_key_s app_key; stc_app_value_s app_value; - if (pkg_id == NULL || app_id == NULL || ip == NULL) { + if (pkg_id == NULL || app_id == NULL || mac == NULL) { STC_LOGE("invalid station station info"); return STC_ERROR_INVALID_PARAMETER; } @@ -48,7 +49,7 @@ static stc_error_e add_station_monitor(gchar *pkg_id, gchar *app_id, const char app_key.app_id = g_strconcat(app_id, STC_TETHERING_APP_SUFFIX, NULL); app_value.type = STC_APP_TYPE_TETHERING; app_value.processes = NULL; - g_strlcpy(app_value.ipaddr, ip, IPV4_IPADDRESS_LEN); + g_strlcpy(app_value.mac, mac, STATION_MAC_STR_LEN); ret = stc_monitor_application_add(app_key, app_value); FREE(app_key.pkg_id); @@ -83,6 +84,14 @@ static int _compare_sta_by_mac_func(gconstpointer a, return g_ascii_strcasecmp(si->mac, (const char *)b); } +static int _compare_sta_by_classid_func(gconstpointer a, + gconstpointer b) +{ + tether_sta_info_s *si = (tether_sta_info_s *)a; + int *classid = (int *)b; + return si->classid - *classid; +} + static int _get_station_info(gconstpointer data, GCompareFunc func, tether_sta_info_s **si) { @@ -142,7 +151,7 @@ static void _add_station_info(tether_sta_info_s *info) if (!g_strcmp0(tmp->name, info->name) && !g_strcmp0(tmp->ip, info->ip)) return; - //Remove the station if dhcp info changed. + /* Remove the station if dhcp info changed. */ _remove_station_info(info->mac, _compare_sta_by_mac_func); } @@ -151,7 +160,7 @@ static void _add_station_info(tether_sta_info_s *info) /* add tethering client for monitoring data usage */ info->station_id = g_strdup_printf("%s_%s", info->mac, info->name); - add_station_monitor(info->mac, info->station_id, info->ip); + add_station_monitor(info->mac, info->station_id, info->mac); } static void _mobileap_signal_cb(GDBusConnection *conn, @@ -182,8 +191,8 @@ static void _mobileap_signal_cb(GDBusConnection *conn, STC_LOGI("%s: ip(%s) mac(%s) name(%s) tm(%d)", state, ip, mac, hostname, tm); if (!g_strcmp0(state, "DhcpConnected")) { - g_strlcpy(sta->ip, ip, STATION_STR_INFO_LEN); - g_strlcpy(sta->mac, mac, STATION_STR_INFO_LEN); + g_strlcpy(sta->ip, ip, INET_ADDRSTRLEN); + g_strlcpy(sta->mac, mac, STATION_MAC_STR_LEN); g_strlcpy(sta->name, hostname, STATION_STR_HOSTNAME_LEN); _add_station_info(sta); } else if (!g_strcmp0(state, "DhcpLeaseDeleted")) { @@ -196,8 +205,59 @@ static void _mobileap_signal_cb(GDBusConnection *conn, g_free(hostname); } -stc_error_e tether_plugin_status_changed(void) +stc_error_e tether_plugin_get_station_ip(const char *mac, char *ip) +{ + tether_sta_info_s *tmp = NULL; + + if (mac == NULL || ip == NULL) + return STC_ERROR_FAIL; + + if (_get_station_info((gconstpointer)mac, + _compare_sta_by_mac_func, &tmp) != 0) { + STC_LOGE("mac(%s) not found", mac); + return STC_ERROR_FAIL; + } + + g_strlcpy(ip, tmp->ip, INET_ADDRSTRLEN); + return STC_ERROR_NONE; +} + +stc_error_e tether_plugin_get_station_by_classid(const int classid, char *mac) +{ + tether_sta_info_s *tmp = NULL; + int classid_value = classid; + + if (mac == NULL) + return STC_ERROR_FAIL; + + if (_get_station_info((gconstpointer)&classid_value, + _compare_sta_by_classid_func, &tmp) != 0) { + STC_LOGE("classid(%s) not found", classid); + return STC_ERROR_FAIL; + } + + g_strlcpy(mac, tmp->mac, STATION_MAC_STR_LEN); + return STC_ERROR_NONE; +} + +stc_error_e tether_plugin_set_station_classid(const char *mac, int classid) { + tether_sta_info_s *tmp = NULL; + + if (mac == NULL) { + STC_LOGE("invalid param"); + return STC_ERROR_FAIL; + } + + if (_get_station_info((gconstpointer)mac, + _compare_sta_by_mac_func, &tmp) != 0) { + STC_LOGE("mac(%s) not found", mac); + return STC_ERROR_FAIL; + } + + if (tmp) + tmp->classid = classid; + return STC_ERROR_NONE; } @@ -244,5 +304,7 @@ void tether_plugin_deinit(void) API stc_plugin_tether_s tether_plugin = { .init = tether_plugin_init, .deinit = tether_plugin_deinit, - .status_changed = tether_plugin_status_changed + .get_station_ip = tether_plugin_get_station_ip, + .get_station_by_classid = tether_plugin_get_station_by_classid, + .set_station_classid = tether_plugin_set_station_classid }; diff --git a/src/database/include/table-restrictions.h b/src/database/include/table-restrictions.h index ea36988..fb62bb9 100644 --- a/src/database/include/table-restrictions.h +++ b/src/database/include/table-restrictions.h @@ -21,6 +21,7 @@ typedef struct { char *app_id; char *ifname; char *subscriber_id; + char *mac; stc_iface_type_e iftype; stc_rstn_type_e rstn_type; stc_roaming_type_e roaming; diff --git a/src/helper/helper-iptables.c b/src/helper/helper-iptables.c index 0914100..445b627 100644 --- a/src/helper/helper-iptables.c +++ b/src/helper/helper-iptables.c @@ -39,7 +39,6 @@ #define RULE_CGROUP "cgroup" #define RULE_NFACCT "nfacct" #define RULE_TARGET "target" -#define RULE_PROTOCOL "protocol" #define RULE_SIPTYPE "s_ip_type" #define RULE_SIP1 "s_ip1" #define RULE_SIP2 "s_ip2" diff --git a/src/helper/helper-nfacct-rule.c b/src/helper/helper-nfacct-rule.c index 70b29a5..d75c3f3 100644 --- a/src/helper/helper-nfacct-rule.c +++ b/src/helper/helper-nfacct-rule.c @@ -285,6 +285,14 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) STRING_SAVE_COPY(cnt->name, cnt_name); +#if 0 + /* ======================================================== + * NOTE:- + * Below parsing for tethering case is not in use + * stc-manager needs to ignore this for NFACCT_TETH_COUNTER + * this is disbaled for future use. + * =======================================================*/ + //LCOV_EXCL_START if (cnt->intend == NFACCT_TETH_COUNTER) { char ifname_buf[MAX_IFACE_LENGTH]; @@ -322,6 +330,7 @@ bool recreate_counter_by_name(char *cnt_name, nfacct_rule_s *cnt) return true; } //LCOV_EXCL_STOP +#endif io_part = strtok_r(name, "_", &save_ptr); if (io_part != NULL) @@ -449,8 +458,10 @@ static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule) iptables_rule.ifname = g_strdup(rule->ifname); iptables_rule.target = g_strdup(get_iptables_jump(rule->jump)); - /* In case of tehering use chain 'STC_TETHER' */ - if (rule->intend == NFACCT_TETH_COUNTER) + /* In case of tehering rules use chain 'STC_TETHER' */ + if (rule->intend == NFACCT_TETH_COUNTER || + rule->intend == NFACCT_TETH_ALLOW || + rule->intend == NFACCT_TETH_BLOCK) iptables_rule.chain = g_strdup(STC_TETHER_CHAIN); else iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype)); @@ -531,7 +542,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule) /* cgroup extention on FORWARD chain are not allowed * remove classid info in case of tethering rules */ - if (rule->intend == NFACCT_TETH_COUNTER) { + if (rule->intend == NFACCT_TETH_COUNTER || + rule->intend == NFACCT_TETH_ALLOW || + rule->intend == NFACCT_TETH_BLOCK) { classid = rule->classid; rule->classid = 0; } @@ -539,7 +552,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule) ret = exec_iptables_cmd(rule); /* restore the classid info in case of tethering rule */ - if (rule->intend == NFACCT_TETH_COUNTER) + if (rule->intend == NFACCT_TETH_COUNTER || + rule->intend == NFACCT_TETH_ALLOW || + rule->intend == NFACCT_TETH_BLOCK) rule->classid = classid; ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, @@ -586,7 +601,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule) /* cgroup extention on FORWARD chain are not allowed * remove classid info in case of tethering rules */ - if (rule->intend == NFACCT_TETH_COUNTER) { + if (rule->intend == NFACCT_TETH_COUNTER || + rule->intend == NFACCT_TETH_ALLOW || + rule->intend == NFACCT_TETH_BLOCK) { classid = rule->classid; rule->classid = 0; } @@ -594,7 +611,9 @@ static stc_error_e produce_app_rule(nfacct_rule_s *rule) ret = exec_iptables_cmd(rule); /* restore the classid info in case of tethering rule */ - if (rule->intend == NFACCT_TETH_COUNTER) + if (rule->intend == NFACCT_TETH_COUNTER || + rule->intend == NFACCT_TETH_ALLOW || + rule->intend == NFACCT_TETH_BLOCK) rule->classid = classid; ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL, @@ -795,12 +814,17 @@ void generate_counter_name(nfacct_rule_s *counter) STRING_SAVE_COPY(counter->ifname, iftype_name); } - if (counter->intend == NFACCT_WARN) + if (counter->intend == NFACCT_WARN || + counter->intend == NFACCT_TETH_WARN) warn_symbol = 'w'; - else if (counter->intend == NFACCT_BLOCK) + else if (counter->intend == NFACCT_BLOCK || + counter->intend == NFACCT_TETH_BLOCK) warn_symbol = 'r'; - else if (counter->intend == NFACCT_ALLOW) + else if (counter->intend == NFACCT_ALLOW || + counter->intend == NFACCT_TETH_ALLOW) warn_symbol = 'a'; + else if (counter->intend == NFACCT_TETH_COUNTER) + warn_symbol = 't'; snprintf(counter->name, NFACCT_NAME_MAX, "%c%d_%d_%d_%s", warn_symbol, counter->iotype, counter->iftype, counter->classid, counter->ifname); diff --git a/src/helper/helper-nfacct-rule.h b/src/helper/helper-nfacct-rule.h index 52ef8f4..7520709 100644 --- a/src/helper/helper-nfacct-rule.h +++ b/src/helper/helper-nfacct-rule.h @@ -56,6 +56,9 @@ typedef enum { NFACCT_BLOCK, NFACCT_ALLOW, NFACCT_TETH_COUNTER, + NFACCT_TETH_WARN, + NFACCT_TETH_BLOCK, + NFACCT_TETH_ALLOW, NFACCT_RULE_LAST_ELEM, } nfacct_rule_intend; diff --git a/src/monitor/include/stc-monitor.h b/src/monitor/include/stc-monitor.h index 187035f..d138cbc 100755 --- a/src/monitor/include/stc-monitor.h +++ b/src/monitor/include/stc-monitor.h @@ -27,7 +27,7 @@ /* 1 seconds */ #define CONTR_TIMER_INTERVAL 1 -#define IPV4_IPADDRESS_LEN 16 +#define MAC_ADDRESS_LEN 18 /** * @brief enumeration for data limit types @@ -78,7 +78,7 @@ typedef struct { stc_data_counter_s data_usage; stc_data_counter_s counter; GTree *processes; /**< applications instances */ - char ipaddr[IPV4_IPADDRESS_LEN+1]; /**< application ip address */ + char mac[MAC_ADDRESS_LEN+1]; /**< application mac address */ } stc_app_value_s; /** @@ -87,6 +87,7 @@ typedef struct { typedef struct { gchar *app_id; gchar *ifname; + gchar *mac; gchar *subscriber_id; stc_iface_type_e iftype; stc_roaming_type_e roaming; diff --git a/src/monitor/stc-monitor.c b/src/monitor/stc-monitor.c index 7f28d9c..8037c53 100755 --- a/src/monitor/stc-monitor.c +++ b/src/monitor/stc-monitor.c @@ -31,6 +31,7 @@ #include "stc-time.h" #include "stc-manager-plugin-appstatus.h" #include "stc-manager-plugin-exception.h" +#include "stc-manager-plugin-tether.h" #define GRANULARITY 10 #define MAX_INT_LENGTH 128 @@ -101,6 +102,10 @@ static nfacct_rule_jump __get_jump_by_intend(struct nfacct_rule *counter) return NFACCT_JUMP_REJECT; else if (counter->intend == NFACCT_ALLOW) return NFACCT_JUMP_ACCEPT; + else if (counter->intend == NFACCT_TETH_BLOCK) + return NFACCT_JUMP_REJECT; + else if (counter->intend == NFACCT_TETH_ALLOW) + return NFACCT_JUMP_ACCEPT; return NFACCT_JUMP_UNKNOWN; } @@ -124,7 +129,7 @@ static stc_error_e __add_iptables_tether_in(struct nfacct_rule *counter, ret = produce_net_rule(counter); - g_free(counter->src_ip1); + FREE(counter->src_ip1); counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE; return ret; } @@ -148,7 +153,7 @@ static stc_error_e __add_iptables_tether_out(struct nfacct_rule *counter, ret = produce_net_rule(counter); - g_free(counter->dst_ip1); + FREE(counter->dst_ip1); counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE; return ret; } @@ -172,7 +177,7 @@ static stc_error_e __del_iptables_tether_in(struct nfacct_rule *counter, ret = produce_net_rule(counter); - g_free(counter->src_ip1); + FREE(counter->src_ip1); counter->src_iprange_type = NFACCT_IPRANGE_TYPE_NONE; return ret; } @@ -196,7 +201,7 @@ static stc_error_e __del_iptables_tether_out(struct nfacct_rule *counter, ret = produce_net_rule(counter); - g_free(counter->dst_ip1); + FREE(counter->dst_ip1); counter->dst_iprange_type = NFACCT_IPRANGE_TYPE_NONE; return ret; } @@ -515,16 +520,19 @@ static gboolean __processes_tree_check_empty(gpointer key, gpointer value, } //LCOV_EXCL_STOP -static gboolean __add_application_monitor_for_tethering(gpointer key, gpointer value, - gpointer data) +static gboolean __add_application_monitor_for_tethering(gpointer key, + gpointer value, gpointer data) { stc_app_value_s *app_value = (stc_app_value_s *)value; stc_app_key_s *app_key = (stc_app_key_s *)key; default_connection_s *connection = (default_connection_s *)data; stc_s *stc = stc_get_manager(); struct nfacct_rule counter; + char *ipaddr = NULL; + int ret; - STC_LOGI("add tether app (%s)", app_key->app_id); + STC_LOGI("add appid(%s) classid(%d)", app_key->app_id, + app_value->classid); if (stc == NULL || connection == NULL) return FALSE; @@ -550,9 +558,16 @@ static gboolean __add_application_monitor_for_tethering(gpointer key, gpointer v counter.iftype = connection->tether_iface.type; g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH); - __add_iptables_tether_in(&counter, app_value->ipaddr); - __add_iptables_tether_out(&counter, app_value->ipaddr); + /* get the ip address of the station based on its mac address */ + ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr); + if (ret != STC_ERROR_NONE) + return FALSE; + + /* tethering iptables rule */ + __add_iptables_tether_in(&counter, ipaddr); + __add_iptables_tether_out(&counter, ipaddr); + g_free(ipaddr); return FALSE; } @@ -564,8 +579,11 @@ static gboolean __remove_application_monitor_for_tethering(gpointer key, gpointe default_connection_s *connection = (default_connection_s *)data; stc_s *stc = stc_get_manager(); struct nfacct_rule counter; + char *ipaddr = NULL; + int ret; - STC_LOGI("remove tether app (%s)", app_key->app_id); + STC_LOGI("remove appid(%s) classid(%d)", app_key->app_id, + app_value->classid); if (stc == NULL || connection == NULL) return FALSE; @@ -591,9 +609,15 @@ static gboolean __remove_application_monitor_for_tethering(gpointer key, gpointe counter.iftype = connection->tether_iface.type; g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH); - __del_iptables_tether_in(&counter, app_value->ipaddr); - __del_iptables_tether_out(&counter, app_value->ipaddr); + /* get the ip address of the station based on its mac address */ + ret = stc_plugin_tether_get_station_ip(app_value->mac, &ipaddr); + if (ret != STC_ERROR_NONE) + return FALSE; + __del_iptables_tether_in(&counter, ipaddr); + __del_iptables_tether_out(&counter, ipaddr); + + g_free(ipaddr); return FALSE; } @@ -784,6 +808,96 @@ static void __add_iptables_rule(int64_t classid, nfacct_rule_intend intend, __add_ip6tables_out(&counter); } +static void __add_tethering_iptables_rule(int64_t classid, gchar *mac, + nfacct_rule_intend intend, stc_iface_type_e iftype) +{ + default_connection_s *connection = stc_get_default_connection(); + struct nfacct_rule counter; + stc_s *stc = stc_get_manager(); + char *ipaddr = NULL; + int ret; + + if (!stc || !mac) + return; + + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + if (stc->carg == NULL) + return; + + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + memset(&counter, 0, sizeof(struct nfacct_rule)); + + counter.carg = stc->carg; + counter.classid = classid; + counter.intend = intend; + + if (connection->tether_state != TRUE || + connection->tether_iface.ifname == NULL) + return; + + counter.iftype = connection->tether_iface.type; + g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH); + + /* get connected station ip based on its mac */ + ret = stc_plugin_tether_get_station_ip(mac, &ipaddr); + if (ret != STC_ERROR_NONE) + return; + + /* tethering iptables rule */ + __add_iptables_tether_in(&counter, ipaddr); + __add_iptables_tether_out(&counter, ipaddr); + g_free(ipaddr); +} + +static void __del_tethering_iptables_rule(int64_t classid, gchar *mac, + nfacct_rule_intend intend, stc_iface_type_e iftype) +{ + default_connection_s *connection = stc_get_default_connection(); + struct nfacct_rule counter; + stc_s *stc = stc_get_manager(); + char *ipaddr = NULL; + int ret; + + if (!stc || !mac) + return; + + if (!stc->carg) { + stc->carg = MALLOC0(counter_arg_s, 1); + if (stc->carg == NULL) + return; + + stc->carg->sock = stc_monitor_get_counter_socket(); + } + + memset(&counter, 0, sizeof(struct nfacct_rule)); + + counter.carg = stc->carg; + counter.classid = classid; + counter.intend = intend; + + if (connection->tether_state != TRUE || + connection->tether_iface.ifname == NULL) + return; + + counter.iftype = connection->tether_iface.type; + g_strlcpy(counter.ifname, connection->tether_iface.ifname, MAX_IFACE_LENGTH); + + /* get connected station ip based on its mac */ + ret = stc_plugin_tether_get_station_ip(mac, &ipaddr); + if (ret != STC_ERROR_NONE) { + STC_LOGE("Error: no IP found for station mac(%s)", mac); + return; + } + + /* tethering iptables rule */ + __del_iptables_tether_in(&counter, ipaddr); + __del_iptables_tether_out(&counter, ipaddr); + g_free(ipaddr); +} + static void __del_iptables_rule(int64_t classid, nfacct_rule_intend intend, stc_iface_type_e iftype) { @@ -872,6 +986,142 @@ static stc_cb_ret_e __statistics_info_cb(const table_statistics_info *info, return STC_CONTINUE; } +static void __process_tethering_restriction(enum traffic_restriction_type rstn_type, + stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value, void *data) +{ + default_connection_s *old_connection = (default_connection_s *)data; + default_connection_s *connection = NULL; + char *mac_str = NULL; + + if (old_connection != NULL) + connection = old_connection; + else + connection = stc_get_default_connection(); + + /* in case tethering is not active */ + if (connection->tether_state == FALSE) + return; + + /* rstn not applicable for this interface */ + if (rstn_key->ifname != NULL && g_strcmp0("", rstn_key->ifname) != 0 && + (g_strcmp0(connection->tether_iface.ifname, rstn_key->ifname) != 0)) + return; + + /* in case appid not a tethering app */ + if (!g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX)) + return; + + /* Ignore TOTAL_TETHERING, + * Process only station appids */ + if (rstn_value->classid == STC_TETHERING_APP_CLASSID) + return; + + /* get the station mac based on classid */ + stc_plugin_tether_get_station_by_classid(rstn_value->classid, &mac_str); + if (!mac_str) { + STC_LOGE("station not found for classid(%d)", rstn_value->classid); + return; + } + + switch (rstn_type) { + case RST_SET: + { + int i; + table_counters_info info; + int64_t effective_limit[STC_RSTN_LIMIT_TYPE_MAX] = { 0, }; + + memset(&info, 0, sizeof(table_counters_info)); + rstn_value->limit_exceeded = 0; + + if ((rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA] == 0 && + rstn_value->limit[STC_RSTN_LIMIT_TYPE_DATA] >= 0) || + (rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] == 0 && + rstn_value->limit[STC_RSTN_LIMIT_TYPE_DATA_WARN] >= 0) || + (rstn_value->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] == 0 && + rstn_value->limit[STC_RSTN_LIMIT_TYPE_MONTHLY] >= 0) || + (rstn_value->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] == 0 && + rstn_value->limit[STC_RSTN_LIMIT_TYPE_WEEKLY] >= 0) || + (rstn_value->counter[STC_RSTN_LIMIT_TYPE_DAILY] == 0 && + rstn_value->limit[STC_RSTN_LIMIT_TYPE_DAILY] >= 0)) { + table_counters_get(rstn_value->restriction_id, &info); + + time_t current_time = 0; + cumulative_data_s stat; + table_statistics_select_rule rule; + + memset(&stat, 0, sizeof(cumulative_data_s)); + stat.month_start_ts = rstn_value->month_start_ts; + stat.week_start_ts = g_system->last_week_ts; + stat.day_start_ts = g_system->last_day_ts; + + memset(&rule, 0, sizeof(table_statistics_select_rule)); + rule.from = rstn_value->month_start_ts; + time(¤t_time); + rule.to = current_time; + rule.iftype = rstn_key->iftype; + rule.granularity = GRANULARITY; + + table_statistics_per_app(rstn_key->app_id, &rule, __statistics_info_cb, &stat); + + rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA] = info.data_counter; + rstn_value->counter[STC_RSTN_LIMIT_TYPE_DATA_WARN] = info.warn_counter; + rstn_value->counter[STC_RSTN_LIMIT_TYPE_MONTHLY] = info.monthly_counter + stat.monthly_stat; + rstn_value->counter[STC_RSTN_LIMIT_TYPE_WEEKLY] = info.weekly_counter + stat.weekly_stat; + rstn_value->counter[STC_RSTN_LIMIT_TYPE_DAILY] = info.daily_counter + stat.daily_stat; + } + + for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) { + if (rstn_value->limit[i] >= 0) { + effective_limit[i] = rstn_value->limit[i] - rstn_value->counter[i]; + + if (effective_limit[i] < 0) + rstn_value->limit_exceeded |= (1 << i); + } + } + + STC_LOGD("rstn_id [%llu], datausage [%llu] bytes", + rstn_value->restriction_id, info.data_counter); + + if (rstn_value->limit_exceeded != 0 && + rstn_value->limit_exceeded != (1 << STC_RSTN_LIMIT_TYPE_DATA_WARN)) { + __add_tethering_iptables_rule(rstn_value->classid, mac_str, + NFACCT_TETH_BLOCK, rstn_key->iftype); + } + + rstn_value->rstn_state = STC_RSTN_STATE_ACTIVATED; + } + break; + case RST_EXCLUDE: + { + __add_tethering_iptables_rule(rstn_value->classid, mac_str, + NFACCT_TETH_ALLOW, rstn_key->iftype); + + rstn_value->rstn_state = STC_RSTN_STATE_ACTIVATED; + rstn_value->limit_exceeded = 0; + rstn_value->limit_notified = 0; + } + break; + case RST_UNSET: + { + int i; + __del_tethering_iptables_rule(rstn_value->classid, mac_str, + NFACCT_TETH_BLOCK, rstn_key->iftype); + + rstn_value->rstn_state = STC_RSTN_STATE_DEACTIVATED; + rstn_value->limit_exceeded = 0; + rstn_value->limit_notified = 0; + + for (i = 0; i < STC_RSTN_LIMIT_TYPE_MAX; i++) + if (rstn_value->limit[i] >= 0) + rstn_value->counter[i] = 0; + } + break; + default: + ;//Do Nothing + } + FREE(mac_str); +} + static void __process_restriction(enum traffic_restriction_type rstn_type, stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value, void *data) @@ -898,6 +1148,13 @@ static void __process_restriction(enum traffic_restriction_type rstn_type, if (rstn_value->classid <= STC_UNKNOWN_CLASSID) return; + /* Do not proceed for tethering station appid if found here, + * for tethering station apps __process_tethering_restriction() call + * will handle it */ + if (g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX) && + rstn_value->classid != STC_TETHERING_APP_CLASSID) + return; + switch (rstn_type) { case RST_SET: { @@ -1024,6 +1281,9 @@ static gboolean __remove_rstns_foreach_application(gpointer key, /* remove restriction from system */ __process_restriction(RST_UNSET, rstn_key, rstn_value, NULL); + /* remove tethering restriction from system*/ + __process_tethering_restriction(RST_UNSET, rstn_key, rstn_value, NULL); + __print_rstn(rstn_key, rstn_value); out: return FALSE; @@ -1125,6 +1385,36 @@ static stc_error_e __close_and_reopen_contr_sock(stc_system_s *system) return STC_ERROR_NONE; } +static void __action_when_rstn_limit_exceeded_tethering(stc_rstn_key_s *rstn_key, + stc_rstn_value_s *rstn_value, classid_bytes_context_s *context) +{ + char *mac_str = NULL; + struct nfacct_rule *counter = context->counter; + + /* get the station mac based on classid */ + stc_plugin_tether_get_station_by_classid(counter->classid, &mac_str); + if (!mac_str) { + STC_LOGE("station not found for classid(%d)", counter->classid); + return; + } + + STC_LOGI("station mac %s, classid %u, iftype %u, iotype %d, \ + intend %d, ifname %s, bytes %lld", mac_str, + counter->classid, counter->iftype, counter->iotype, + counter->intend, counter->ifname, context->bytes); + + /* Block tethering station immediately */ + counter->intend = NFACCT_TETH_BLOCK; + __del_tethering_iptables_rule(counter->classid, mac_str, + NFACCT_TETH_BLOCK, rstn_key->iftype); + + __add_tethering_iptables_rule(counter->classid, mac_str, + NFACCT_TETH_BLOCK, rstn_key->iftype); + counter->intend = NFACCT_TETH_COUNTER; + + g_free(mac_str); +} + static void __action_when_rstn_limit_exceeded(stc_rstn_limit_type_e limit_type, stc_rstn_key_s *rstn_key, stc_rstn_value_s *rstn_value, @@ -1160,18 +1450,30 @@ static void __action_when_rstn_limit_exceeded(stc_rstn_limit_type_e limit_type, net_popup_content = "restriction threshold crossed"; net_popup_type = "restriction_noti"; - /* block immediately */ - context->counter->intend = NFACCT_BLOCK; - __del_iptables_in(context->counter); - __del_iptables_out(context->counter); - __add_iptables_in(context->counter); - __add_iptables_out(context->counter); + /* Apply restriction for tethering apps if app_id is of tethering client + * otherwise do the normal iptables rule */ + if (context->counter->intend == NFACCT_TETH_COUNTER) { - __del_ip6tables_in(context->counter); - __del_ip6tables_out(context->counter); - __add_ip6tables_in(context->counter); - __add_ip6tables_out(context->counter); - context->counter->intend = NFACCT_COUNTER; + if (g_str_has_suffix(rstn_key->app_id, STC_TETHERING_APP_SUFFIX) && + rstn_value->classid != STC_TETHERING_APP_CLASSID) { + __action_when_rstn_limit_exceeded_tethering(rstn_key, rstn_value, + context); + } + + } else { + /* block immediately */ + context->counter->intend = NFACCT_BLOCK; + __del_iptables_in(context->counter); + __del_iptables_out(context->counter); + __add_iptables_in(context->counter); + __add_iptables_out(context->counter); + + __del_ip6tables_in(context->counter); + __del_ip6tables_out(context->counter); + __add_ip6tables_in(context->counter); + __add_ip6tables_out(context->counter); + context->counter->intend = NFACCT_COUNTER; + } rstn_value->limit_exceeded |= (1 << limit_type); @@ -1877,6 +2179,7 @@ static gboolean __remove_restriction(gpointer key, gpointer value, stc_rstn_value_s *rstn_value = (stc_rstn_value_s *)value; __process_restriction(RST_UNSET, rstn_key, rstn_value, data); + __process_tethering_restriction(RST_UNSET, rstn_key, rstn_value, data); __print_rstn(rstn_key, rstn_value); return FALSE; } @@ -1891,10 +2194,13 @@ static gboolean __add_restriction_debug(gpointer key, gpointer value, if (rstn_value->rstn_state == STC_RSTN_STATE_ACTIVATED) return FALSE; - if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) + if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) { __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); - else + __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); + } else { __process_restriction(RST_SET, rstn_key, rstn_value, data); + __process_tethering_restriction(RST_SET, rstn_key, rstn_value, data); + } __print_rstn(rstn_key, rstn_value); @@ -1911,10 +2217,13 @@ static gboolean __add_restriction(gpointer key, gpointer value, gpointer data) if (rstn_value->rstn_state == STC_RSTN_STATE_ACTIVATED) return FALSE; - if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) + if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) { __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); - else + __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, data); + } else { __process_restriction(RST_SET, rstn_key, rstn_value, data); + __process_tethering_restriction(RST_SET, rstn_key, rstn_value, data); + } return FALSE; } @@ -1971,6 +2280,7 @@ static stc_error_e __rstn_tree_add(stc_rstn_key_s *key, rstn_key->app_id = g_strdup(key->app_id); rstn_key->ifname = g_strdup(key->ifname); + rstn_key->mac = g_strdup(key->mac); rstn_key->subscriber_id = g_strdup(key->subscriber_id); rstn_key->iftype = key->iftype; rstn_key->roaming = key->roaming; @@ -2071,10 +2381,13 @@ static gboolean __add_rstn_foreach_application(gpointer key, goto out; /* add restriction to system */ - if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) + if (rstn_value->rstn_type == STC_RSTN_TYPE_ACCEPT) { __process_restriction(RST_EXCLUDE, rstn_key, rstn_value, NULL); - else + __process_tethering_restriction(RST_EXCLUDE, rstn_key, rstn_value, NULL); + } else { __process_restriction(RST_SET, rstn_key, rstn_value, NULL); + __process_tethering_restriction(RST_SET, rstn_key, rstn_value, NULL); + } __print_rstn(rstn_key, rstn_value); out: @@ -2293,7 +2606,7 @@ API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key, value->type = app_value.type; value->data_usage.in_bytes = app_value.data_usage.in_bytes; value->data_usage.out_bytes = app_value.data_usage.out_bytes; - g_strlcpy(value->ipaddr, app_value.ipaddr, IPV4_IPADDRESS_LEN); + g_strlcpy(value->mac, app_value.mac, MAC_ADDRESS_LEN); value->processes = g_tree_new_full(__processes_tree_key_compare, NULL, __processes_tree_key_free, @@ -2302,6 +2615,11 @@ API stc_error_e stc_monitor_application_add(const stc_app_key_s app_key, /* create cgroup and update classid */ value->classid = get_classid_by_app_id(app_key.app_id, TRUE); + /* update classid for tethering station based on its mac address */ + if (g_str_has_suffix(app_key.app_id, STC_TETHERING_APP_SUFFIX) && + value->classid != STC_TETHERING_APP_CLASSID) + stc_plugin_tether_set_station_classid(value->mac, value->classid); + g_tree_insert(g_system->apps, key, value); /* add nfacct rule for this classid */ @@ -2517,6 +2835,7 @@ stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info) key.app_id = g_strdup(info->app_id); key.ifname = g_strdup(info->ifname); + key.mac = g_strdup(info->mac); key.subscriber_id = g_strdup(info->subscriber_id); key.iftype = info->iftype; key.roaming = info->roaming; @@ -2549,6 +2868,7 @@ stc_error_e stc_monitor_rstns_tree_add(const table_restrictions_info *info) FREE(key.app_id); FREE(key.ifname); + FREE(key.mac); FREE(key.subscriber_id); return ret; } diff --git a/src/stc-manager-plugin-tether.c b/src/stc-manager-plugin-tether.c index 1813e40..afb170d 100644 --- a/src/stc-manager-plugin-tether.c +++ b/src/stc-manager-plugin-tether.c @@ -65,3 +65,69 @@ int stc_plugin_tether_deinit(void) __STC_LOG_FUNC_EXIT__; return STC_ERROR_NONE; } + +int stc_plugin_tether_get_station_ip(const char *mac, char **ipaddr) +{ + __STC_LOG_FUNC_ENTER__; + char ip[INET_ADDRSTRLEN+1]; + + if (!stc_tether_plugin_enabled || + mac == NULL || ipaddr == NULL) { + STC_LOGE("invalid args"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + memset(ip, 0, sizeof(ip)); + + if (plugin->get_station_ip(mac, ip) != STC_ERROR_NONE) + return STC_ERROR_FAIL; + + *ipaddr = g_strdup(ip); + STC_LOGI("station ip(%s)", *ipaddr); + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +int stc_plugin_tether_get_station_by_classid(const int classid, char **mac) +{ + __STC_LOG_FUNC_ENTER__; + char mac_addr[STATION_MAC_STR_LEN+1]; + + if (!stc_tether_plugin_enabled || mac == NULL) { + STC_LOGE("invalid args"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + memset(mac_addr, 0, sizeof(mac_addr)); + + if (plugin->get_station_by_classid(classid, mac_addr) != STC_ERROR_NONE) + return STC_ERROR_FAIL; + + *mac = g_strdup(mac_addr); + STC_LOGI("station mac(%s)", *mac); + + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} + +int stc_plugin_tether_set_station_classid(const char *mac, int classid) +{ + __STC_LOG_FUNC_ENTER__; + + if (!stc_tether_plugin_enabled || mac == NULL) { + STC_LOGE("invalid args"); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_INVALID_PARAMETER; + } + + if (plugin->set_station_classid(mac, classid) != STC_ERROR_NONE) + return STC_ERROR_FAIL; + + STC_LOGI("classid(%d) for station mac(%s) is set successfully", + classid, mac); + __STC_LOG_FUNC_EXIT__; + return STC_ERROR_NONE; +} diff --git a/src/stc-restriction.c b/src/stc-restriction.c index 2f44459..f4cd753 100644 --- a/src/stc-restriction.c +++ b/src/stc-restriction.c @@ -241,6 +241,12 @@ static void __stc_extract_restriction_rule(const char *key, GVariant *value, rule->rstn_type = g_variant_get_uint16(value); STC_LOGD("type: [%u]", (unsigned int) rule->rstn_type); + } else if (!g_strcmp0(key, "mac")) { + guint str_length; + const gchar *str = g_variant_get_string(value, &str_length); + rule->mac = g_strdup(str); + STC_LOGD("mac: [%s]", rule->mac); + } else { STC_LOGD("Unknown select rule"); //LCOV_EXCL_LINE } -- 2.7.4