+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stc-plugin-firewall.h"
+#include "table-firewall.h"
+#include "helper-firewall.h"
+
+#define LOCK_NAME "admin"
+
+#define IDENTIFIER_LEN 512
+
+#define CHAIN_NAME "chain"
+#define CHAIN_TARGET "target"
+#define CHAIN_PRIORITY "priority"
+
+#define RULE_IDENTIFIER "identifier"
+#define RULE_KEY "key"
+
+#define STC_FIREWALL_CHECK_LOCK_STATE() do { \
+ if (g_lock_state == FIREWALL_LOCKED) { \
+ if (STC_FW_LOG) \
+ STC_LOGD("Firewall is locked"); \
+ return STC_ERROR_PERMISSION_DENIED; \
+ } \
+} while (0)
+
+static GHashTable *g_firewalls = NULL;
+static int g_lock_state = FIREWALL_UNKONWN;
+static int g_chain_priority = 0;
+
+static void __fw_rule_copy(firewall_rule_s *rule,
+ const firewall_rule_s *info)
+{
+ if (info->chain) {
+ FREE(rule->chain);
+ rule->chain = g_strdup(info->chain);
+ }
+
+ rule->direction = info->direction;
+ rule->s_ip_type = info->s_ip_type;
+ rule->d_ip_type = info->d_ip_type;
+ rule->s_port_type = info->s_port_type;
+ rule->d_port_type = info->d_port_type;
+ rule->protocol = info->protocol;
+ rule->family = info->family;
+
+ rule->s_ip1 = info->s_ip1;
+ rule->s_ip2 = info->s_ip2;
+ rule->d_ip1 = info->d_ip1;
+ rule->d_ip2 = info->d_ip2;
+
+ rule->s_port1 = info->s_port1;
+ rule->s_port2 = info->s_port2;
+ rule->d_port1 = info->d_port1;
+ rule->d_port2 = info->d_port2;
+
+ if (info->ifname) {
+ FREE(rule->ifname);
+ rule->ifname = g_strdup(info->ifname);
+ }
+
+ rule->target = info->target;
+
+ if (info->target_str) {
+ FREE(rule->target_str);
+ rule->target_str = g_strdup(info->target_str);
+ }
+
+ rule->log_level = info->log_level;
+
+ if (info->log_prefix) {
+ FREE(rule->log_prefix);
+ rule->log_prefix = g_strdup(info->log_prefix);
+ }
+
+ rule->nflog_group = info->nflog_group;
+ rule->nflog_range = info->nflog_range;
+ rule->nflog_threshold = info->nflog_threshold;
+
+ if (info->nflog_prefix) {
+ FREE(rule->nflog_prefix);
+ rule->nflog_prefix = g_strdup(info->nflog_prefix);
+ }
+
+ if (info->identifier) {
+ FREE(rule->identifier);
+ rule->identifier = g_strdup(info->identifier);
+ }
+
+ rule->key = info->key;
+}
+
+static void __fw_rule_make_key(firewall_rule_s *rule,
+ firewall_rule_s *info)
+{
+ GString *str;
+
+ if (!rule->chain)
+ return;
+
+ str = g_string_sized_new(IDENTIFIER_LEN);
+ if (!str)
+ return;
+
+ g_string_append_printf(str, "%s", rule->chain);
+
+ g_string_append_printf(str, "_%u%u%u%u%u%u%u", rule->direction,
+ rule->s_ip_type, rule->d_ip_type, rule->s_port_type,
+ rule->d_port_type, rule->protocol, rule->family);
+
+ if (rule->family == STC_FW_FAMILY_V4) {
+ g_string_append_printf(str, "_");
+ g_string_append_printf(str, "%08x", rule->s_ip1.Ipv4.s_addr);
+ g_string_append_printf(str, "%08x", rule->s_ip2.Ipv4.s_addr);
+
+ g_string_append_printf(str, "_");
+ g_string_append_printf(str, "%08x", rule->d_ip1.Ipv4.s_addr);
+ g_string_append_printf(str, "%08x", rule->d_ip2.Ipv4.s_addr);
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ g_string_append_printf(str, "_");
+ g_string_append_printf(str, "%08x", rule->s_ip1.Ipv6.s6_addr32[0]);
+ g_string_append_printf(str, "%08x", rule->s_ip1.Ipv6.s6_addr32[1]);
+ g_string_append_printf(str, "%08x", rule->s_ip1.Ipv6.s6_addr32[2]);
+ g_string_append_printf(str, "%08x", rule->s_ip1.Ipv6.s6_addr32[3]);
+ g_string_append_printf(str, "%08x", rule->s_ip2.Ipv6.s6_addr32[0]);
+ g_string_append_printf(str, "%08x", rule->s_ip2.Ipv6.s6_addr32[1]);
+ g_string_append_printf(str, "%08x", rule->s_ip2.Ipv6.s6_addr32[2]);
+ g_string_append_printf(str, "%08x", rule->s_ip2.Ipv6.s6_addr32[3]);
+
+ g_string_append_printf(str, "_");
+ g_string_append_printf(str, "%08x", rule->d_ip1.Ipv6.s6_addr32[0]);
+ g_string_append_printf(str, "%08x", rule->d_ip1.Ipv6.s6_addr32[1]);
+ g_string_append_printf(str, "%08x", rule->d_ip1.Ipv6.s6_addr32[2]);
+ g_string_append_printf(str, "%08x", rule->d_ip1.Ipv6.s6_addr32[3]);
+ g_string_append_printf(str, "%08x", rule->d_ip2.Ipv6.s6_addr32[0]);
+ g_string_append_printf(str, "%08x", rule->d_ip2.Ipv6.s6_addr32[1]);
+ g_string_append_printf(str, "%08x", rule->d_ip2.Ipv6.s6_addr32[2]);
+ g_string_append_printf(str, "%08x", rule->d_ip2.Ipv6.s6_addr32[3]);
+ }
+
+ g_string_append_printf(str, "_%04x", rule->s_port1);
+ g_string_append_printf(str, "%04x", rule->s_port2);
+
+ g_string_append_printf(str, "_%04x", rule->d_port1);
+ g_string_append_printf(str, "%04x", rule->d_port2);
+
+ g_string_append_printf(str, "_%s", (rule->ifname) ? rule->ifname : "");
+ g_string_append_printf(str, "_%u", rule->target);
+
+ switch (rule->target) {
+ case STC_FW_RULE_TARGET_LOG:
+ g_string_append_printf(str, "_%u", rule->log_level);
+ g_string_append_printf(str, "_%s", rule->log_prefix);
+ break;
+ case STC_FW_RULE_TARGET_NFLOG:
+ g_string_append_printf(str, "_%u", rule->nflog_group);
+ g_string_append_printf(str, "_%s", rule->nflog_prefix);
+ g_string_append_printf(str, "_%u", rule->nflog_range);
+ g_string_append_printf(str, "_%u", rule->nflog_threshold);
+ break;
+ default:
+ break;
+ }
+
+ FREE(rule->identifier);
+ rule->identifier = g_string_free(str, FALSE);
+ rule->key = g_str_hash(rule->identifier);
+
+ FREE(info->identifier);
+ info->identifier = g_strdup(rule->identifier);
+ info->key = rule->key;
+
+ if (STC_DEBUG_LOG && STC_FW_LOG) {
+ STC_LOGD("Identifier [%s]", rule->identifier);
+ STC_LOGD("Key [%u]", rule->key);
+ }
+}
+
+static void __fw_rule_free(void *data)
+{
+ firewall_rule_s *rule = (firewall_rule_s *)data;
+
+ FREE(rule->chain);
+ FREE(rule->ifname);
+ FREE(rule->target_str);
+ FREE(rule->log_prefix);
+ FREE(rule->nflog_prefix);
+ FREE(rule->identifier);
+ FREE(rule);
+}
+
+static void __fw_data_free(gpointer value)
+{
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+
+ g_slist_free_full(data->rules, __fw_rule_free);
+ data->rules = NULL;
+
+ FREE(data);
+}
+
+static gint __fw_rule_comp(gconstpointer a, gconstpointer b)
+{
+ firewall_rule_s *data = (firewall_rule_s *)a;
+ firewall_rule_s *rule = (firewall_rule_s *)b;
+
+ if ((data->key == rule->key) &&
+ (g_strcmp0(data->identifier, rule->identifier) == 0))
+ return 0;
+
+ return -1;
+}
+
+static stc_error_e __fw_chain_add(const char *chain)
+{
+ stc_fw_data_s *data;
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGD("chain already present");
+ return STC_ERROR_ALREADY_DATA;
+ }
+
+ data = MALLOC0(stc_fw_data_s, 1);
+ if (!data) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("data allocation failed");
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ data->target = STC_FW_CHAIN_TARGET_NONE;
+ data->priority = 0;
+ data->rules = NULL;
+
+ g_hash_table_insert(g_firewalls, g_strdup(chain), data);
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __fw_chain_remove(const char *chain)
+{
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("can't be applied bcz chain is set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ g_slist_free_full(lookup->rules, __fw_rule_free);
+ lookup->rules = NULL;
+
+ g_hash_table_remove(g_firewalls, chain);
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __fw_chain_flush(const char *chain)
+{
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("can't be applied bcz chain is set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ g_slist_free_full(lookup->rules, __fw_rule_free);
+ lookup->rules = NULL;
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __fw_chain_set(const char *chain, stc_fw_data_s value)
+{
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ lookup->target = value.target;
+ lookup->priority = value.priority;
+
+ return STC_ERROR_NONE;
+}
+
+static stc_fw_data_s *__fw_chain_get(const char *chain)
+{
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL, NULL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return NULL;
+ }
+
+ return lookup;
+}
+
+static stc_error_e __fw_chain_unset(const char *chain)
+{
+ stc_error_e ret = STC_ERROR_NONE;
+ stc_fw_data_s *lookup;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ lookup->target = STC_FW_CHAIN_TARGET_NONE;
+ lookup->priority = 0;
+
+ return ret;
+}
+
+static void __fw_chain_make_params(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ char *chain = (char *)key;
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+ GVariantBuilder *builder = (GVariantBuilder *)user_data;
+ GVariantBuilder sub_builder;
+
+ g_variant_builder_init(&sub_builder, G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(&sub_builder, "{sv}", CHAIN_NAME,
+ g_variant_new_string(chain));
+
+ g_variant_builder_add(&sub_builder, "{sv}", CHAIN_PRIORITY,
+ g_variant_new_uint32(data->priority));
+
+ g_variant_builder_add(&sub_builder, "{sv}", CHAIN_TARGET,
+ g_variant_new_uint16(data->target));
+
+ g_variant_builder_add_value(builder, g_variant_builder_end(&sub_builder));
+}
+
+static void __fw_rule_make_params(gpointer data, gpointer user_data)
+{
+ firewall_rule_s *rule = (firewall_rule_s *)data;
+ GVariantBuilder *builder = (GVariantBuilder *)user_data;
+ GVariantBuilder sub_builder;
+
+ g_variant_builder_init(&sub_builder, G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_CHAIN,
+ g_variant_new_string(rule->chain));
+
+ if (rule->direction != STC_FW_DIRECTION_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIRECTION,
+ g_variant_new_uint16(rule->direction));
+
+ if (rule->s_ip_type != STC_FW_IP_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SIPTYPE,
+ g_variant_new_uint16(rule->s_ip_type));
+
+ if (rule->d_ip_type != STC_FW_IP_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIPTYPE,
+ g_variant_new_uint16(rule->d_ip_type));
+
+ if (rule->s_port_type != STC_FW_PORT_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SPORTTYPE,
+ g_variant_new_uint16(rule->s_port_type));
+
+ if (rule->d_port_type != STC_FW_PORT_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DPORTTYPE,
+ g_variant_new_uint16(rule->d_port_type));
+
+ if (rule->protocol != STC_FW_PROTOCOL_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_PROTOCOL,
+ g_variant_new_uint16(rule->protocol));
+
+ if (rule->family != STC_FW_FAMILY_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_FAMILY,
+ g_variant_new_uint16(rule->family));
+
+ if (rule->family == STC_FW_FAMILY_V4) {
+ char *addr = NULL;
+
+ switch (rule->s_ip_type) {
+ case STC_FW_IP_RANGE:
+ /* fall through */
+ case STC_FW_IP_MASK:
+ addr = g_try_malloc0(INET_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET, &(rule->s_ip2.Ipv4), addr, INET_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SIP2,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ /* fall through */
+ case STC_FW_IP_SINGLE:
+ addr = g_try_malloc0(INET_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET, &(rule->s_ip1.Ipv4), addr, INET_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SIP1,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (rule->d_ip_type) {
+ case STC_FW_IP_RANGE:
+ /* fall through */
+ case STC_FW_IP_MASK:
+ addr = g_try_malloc0(INET_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET, &(rule->d_ip2.Ipv4), addr, INET_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIP2,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ /* fall through */
+ case STC_FW_IP_SINGLE:
+ addr = g_try_malloc0(INET_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET, &(rule->d_ip1.Ipv4), addr, INET_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIP1,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ char *addr = NULL;
+
+ switch (rule->s_ip_type) {
+ case STC_FW_IP_RANGE:
+ /* fall through */
+ case STC_FW_IP_MASK:
+ addr = g_try_malloc0(INET6_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET6, &(rule->s_ip2.Ipv6), addr, INET6_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SIP2,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ /* fall through */
+ case STC_FW_IP_SINGLE:
+ addr = g_try_malloc0(INET6_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET6, &(rule->s_ip1.Ipv6), addr, INET6_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SIP1,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (rule->d_ip_type) {
+ case STC_FW_IP_RANGE:
+ /* fall through */
+ case STC_FW_IP_MASK:
+ addr = g_try_malloc0(INET6_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET6, &(rule->d_ip2.Ipv6), addr, INET6_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIP2,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ /* fall through */
+ case STC_FW_IP_SINGLE:
+ addr = g_try_malloc0(INET6_ADDRSTRLEN);
+ if (addr) {
+ inet_ntop(AF_INET6, &(rule->d_ip1.Ipv6), addr, INET6_ADDRSTRLEN);
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DIP1,
+ g_variant_new_string(addr));
+ FREE(addr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SPORT1,
+ g_variant_new_uint32(rule->s_port1));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_SPORT2,
+ g_variant_new_uint32(rule->s_port2));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DPORT1,
+ g_variant_new_uint32(rule->d_port1));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_DPORT2,
+ g_variant_new_uint32(rule->d_port2));
+
+ if (rule->ifname)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_IFNAME,
+ g_variant_new_string(rule->ifname));
+
+ if (rule->target != STC_FW_RULE_TARGET_NONE)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_TARGET,
+ g_variant_new_uint16(rule->target));
+
+ switch (rule->target) {
+ case STC_FW_RULE_TARGET_LOG:
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_LOG_LEVEL,
+ g_variant_new_uint16(rule->log_level));
+
+ if (rule->log_prefix)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_LOG_PREFIX,
+ g_variant_new_string(rule->log_prefix));
+ break;
+ case STC_FW_RULE_TARGET_NFLOG:
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_NFLOG_GROUP,
+ g_variant_new_uint16(rule->nflog_group));
+
+ if (rule->nflog_prefix)
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_NFLOG_PREFIX,
+ g_variant_new_string(rule->nflog_prefix));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_NFLOG_RANGE,
+ g_variant_new_uint16(rule->nflog_range));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_NFLOG_THRESHOLD,
+ g_variant_new_uint16(rule->nflog_threshold));
+ break;
+ default:
+ break;
+ }
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_IDENTIFIER,
+ g_variant_new_string(rule->identifier));
+
+ g_variant_builder_add(&sub_builder, "{sv}", RULE_KEY,
+ g_variant_new_uint32(rule->key));
+
+ g_variant_builder_add_value(builder, g_variant_builder_end(&sub_builder));
+}
+
+static void __fw_rule_set_to_chain(gpointer data, gpointer user_data)
+{
+ firewall_rule_s *rule = (firewall_rule_s *)data;
+ char *chain = (char *)user_data;
+
+ if (chain && (g_strcmp0(rule->chain, chain) != 0))
+ return;
+
+ switch (rule->target) {
+ case STC_FW_RULE_TARGET_ACCEPT:
+ FREE(rule->target_str);
+ rule->target_str = g_strdup(FIREWALL_RULE_TARGET_ACCEPT);
+ break;
+ case STC_FW_RULE_TARGET_DROP:
+ FREE(rule->target_str);
+ rule->target_str = g_strdup(FIREWALL_RULE_TARGET_DROP);
+ break;
+ case STC_FW_RULE_TARGET_LOG:
+ FREE(rule->target_str);
+ rule->target_str = g_strdup(FIREWALL_RULE_TARGET_LOG);
+ break;
+ case STC_FW_RULE_TARGET_NFLOG:
+ FREE(rule->target_str);
+ rule->target_str = g_strdup(FIREWALL_RULE_TARGET_NFLOG);
+ break;
+ default:
+ break;
+ }
+
+ firewall_rule_append(rule);
+}
+
+static void __fw_rule_print_rules(gpointer data, gpointer user_data)
+{
+ firewall_rule_s *rule = (firewall_rule_s *)data;
+
+ STC_LOGD("[%s][%d][%s][%d][%d][%04x][%04x]"
+ "[%d][%04x][%04x][%d][%s][%d][%s][%d][%d]",
+ rule->chain, rule->direction, rule->ifname,
+ rule->protocol,
+ rule->s_port_type, rule->s_port1, rule->s_port2,
+ rule->d_port_type, rule->d_port1, rule->d_port2,
+ rule->target, rule->target_str,
+ rule->nflog_group, rule->nflog_prefix,
+ rule->nflog_range, rule->nflog_threshold);
+
+ switch (rule->family) {
+ case STC_FW_FAMILY_V4:
+ STC_LOGD("[%d][%d][%08x][%08x][%d][%08x][%08x]",
+ rule->family,
+ rule->s_ip_type, rule->s_ip1.Ipv4.s_addr, rule->s_ip2.Ipv4.s_addr,
+ rule->d_ip_type, rule->d_ip1.Ipv4.s_addr, rule->d_ip2.Ipv4.s_addr);
+ break;
+ case STC_FW_FAMILY_V6:
+ STC_LOGD("[%d][%d][%08x:%08x:%08x:%08x]"
+ "[%d][%08x:%08x:%08x:%08x]",
+ rule->family,
+ rule->s_ip_type,
+ rule->s_ip1.Ipv6.s6_addr32[0], rule->s_ip1.Ipv6.s6_addr32[1],
+ rule->s_ip1.Ipv6.s6_addr32[2], rule->s_ip1.Ipv6.s6_addr32[3],
+ rule->d_ip_type,
+ rule->d_ip1.Ipv6.s6_addr32[0], rule->d_ip1.Ipv6.s6_addr32[1],
+ rule->d_ip1.Ipv6.s6_addr32[2], rule->d_ip1.Ipv6.s6_addr32[3]);
+ break;
+ default:
+ break;
+ }
+}
+
+static void __fw_foreach_to_print_rule(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+
+ g_slist_foreach(data->rules, __fw_rule_print_rules, user_data);
+}
+
+static void __fw_foreach_to_make_rule_param(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+
+ g_slist_foreach(data->rules, __fw_rule_make_params, user_data);
+}
+
+static void __fw_foreach_to_set_rule_to_chain(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+ char *chain = (char *)user_data;
+
+ if (chain || (data->target != STC_FW_CHAIN_TARGET_NONE))
+ g_slist_foreach(data->rules, __fw_rule_set_to_chain, user_data);
+}
+
+static void __fw_foreach_to_set_chain(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ char *chain = (char *)key;
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+
+ if (data->target != STC_FW_CHAIN_TARGET_NONE) {
+ firewall_chain_s info;
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ info.target = data->target;
+ info.priority = data->priority;
+ firewall_chain_set(&info);
+ }
+}
+
+static void __fw_foreach_to_add_chain(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ char *chain = (char *)key;
+ stc_fw_data_s *data = (stc_fw_data_s *)value;
+
+ if (data->target != STC_FW_CHAIN_TARGET_NONE) {
+ firewall_chain_s info;
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ info.target = data->target;
+ info.priority = data->priority;
+ firewall_chain_add(&info);
+ }
+}
+
+static void __fw_chain_foreach(GHFunc func, void *user_data)
+{
+ g_hash_table_foreach(g_firewalls, func, user_data);
+}
+
+stc_cb_ret_e __fw_table_chain_info_cb(const firewall_chain_s *info,
+ void *user_data)
+{
+ stc_fw_data_s *data;
+
+ data = MALLOC0(stc_fw_data_s, 1);
+ if (!data) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("data allocation failed");
+ return STC_CONTINUE;
+ }
+
+ data->target = info->target;
+ data->priority = info->priority;
+ data->rules = NULL;
+
+ g_hash_table_insert(g_firewalls, g_strdup(info->chain), data);
+
+ return STC_CONTINUE;
+}
+
+stc_cb_ret_e __fw_table_rule_info_cb(const firewall_rule_s *info,
+ void *user_data)
+{
+ stc_fw_data_s *lookup;
+ firewall_rule_s *rule;
+
+ lookup = g_hash_table_lookup(g_firewalls, info->chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_CONTINUE;
+ }
+
+ rule = MALLOC0(firewall_rule_s, 1);
+ if (!rule) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("rule allocation failed");
+ return STC_CONTINUE;
+ }
+
+ memset(rule, 0, sizeof(firewall_rule_s));
+ __fw_rule_copy(rule, info);
+
+ lookup->rules = g_slist_append(lookup->rules, rule);
+
+ return STC_CONTINUE;
+}
+
+static stc_error_e __fw_rule_add(firewall_rule_s *info)
+{
+ stc_fw_data_s *lookup;
+ firewall_rule_s *rule;
+ GSList *comp;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, info->chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("can't be applied bcz chain is set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ rule = MALLOC0(firewall_rule_s, 1);
+ if (!rule) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("rule allocation failed");
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(rule, 0, sizeof(firewall_rule_s));
+ __fw_rule_copy(rule, info);
+ __fw_rule_make_key(rule, info);
+
+ comp = g_slist_find_custom(lookup->rules, rule, __fw_rule_comp);
+ if (comp) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGD("rule already present");
+ __fw_rule_free(rule);
+ return STC_ERROR_ALREADY_DATA;
+ }
+
+ lookup->rules = g_slist_append(lookup->rules, rule);
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __fw_rule_remove(const firewall_rule_s *info)
+{
+ stc_fw_data_s *lookup;
+ GSList *rule_list;
+ GSList *comp;
+ firewall_rule_s *rule;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, info->chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("can't be applied bcz chain is set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ rule_list = lookup->rules;
+ comp = g_slist_find_custom(rule_list, info, __fw_rule_comp);
+ if (!comp) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGD("rule not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ rule = comp->data;
+ lookup->rules = g_slist_remove(lookup->rules, rule);
+ __fw_rule_free(rule);
+
+ return STC_ERROR_NONE;
+}
+
+static stc_error_e __fw_rule_update(firewall_rule_s *info)
+{
+ stc_fw_data_s *lookup;
+ GSList *rule_list;
+ GSList *comp;
+ firewall_rule_s *origin_rule;
+ firewall_rule_s *update_rule;
+
+ ret_value_msg_if(g_firewalls == NULL,
+ STC_ERROR_FAIL,
+ "firewall is not initialized!");
+
+ lookup = g_hash_table_lookup(g_firewalls, info->chain);
+ if (!lookup) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("chain not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("can't be applied bcz chain is set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ rule_list = lookup->rules;
+ comp = g_slist_find_custom(rule_list, info, __fw_rule_comp);
+ if (!comp) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGD("rule not found");
+ return STC_ERROR_NO_DATA;
+ }
+
+ origin_rule = comp->data;
+
+ update_rule = MALLOC0(firewall_rule_s, 1);
+ if (!update_rule) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGE("rule allocation failed");
+ return STC_ERROR_OUT_OF_MEMORY;
+ }
+
+ memset(update_rule, 0, sizeof(firewall_rule_s));
+ __fw_rule_copy(update_rule, info);
+ __fw_rule_make_key(update_rule, info);
+
+ comp = g_slist_find_custom(lookup->rules, update_rule, __fw_rule_comp);
+ if (comp) {
+ if (STC_DEBUG_LOG && STC_FW_LOG)
+ STC_LOGD("rule already present");
+ __fw_rule_free(update_rule);
+ return STC_ERROR_ALREADY_DATA;
+ }
+
+ lookup->rules = g_slist_remove(lookup->rules, origin_rule);
+ __fw_rule_free(origin_rule);
+
+ lookup->rules = g_slist_append(lookup->rules, update_rule);
+
+ return STC_ERROR_NONE;
+}
+
+static void __fw_rule_extract(const char *key, GVariant *value,
+ void *user_data)
+{
+ firewall_rule_s *rule = (firewall_rule_s *)user_data;
+ if (rule == NULL) {
+ __STC_LOG_FUNC_EXIT__;
+ return;
+ }
+
+ if (g_strcmp0(key, RULE_CHAIN) == 0) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ rule->chain = g_strdup(str);
+ STC_LOGD("%s: [%s]", RULE_CHAIN, rule->chain);
+
+ } else if (g_strcmp0(key, RULE_DIRECTION) == 0) {
+ rule->direction = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_DIRECTION, rule->direction);
+
+ } else if (g_strcmp0(key, RULE_SIPTYPE) == 0) {
+ rule->s_ip_type = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_SIPTYPE, rule->s_ip_type);
+
+ } else if (g_strcmp0(key, RULE_DIPTYPE) == 0) {
+ rule->d_ip_type = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_DIPTYPE, rule->d_ip_type);
+
+ } else if (g_strcmp0(key, RULE_SPORTTYPE) == 0) {
+ rule->s_port_type = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_SPORTTYPE, rule->s_port_type);
+
+ } else if (g_strcmp0(key, RULE_DPORTTYPE) == 0) {
+ rule->d_port_type = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_DPORTTYPE, rule->d_port_type);
+
+ } else if (g_strcmp0(key, RULE_PROTOCOL) == 0) {
+ rule->protocol = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_PROTOCOL, rule->protocol);
+
+ } else if (g_strcmp0(key, RULE_FAMILY) == 0) {
+ rule->family = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_FAMILY, rule->family);
+
+ } else if (g_strcmp0(key, RULE_SIP1) == 0) {
+ if (rule->s_ip_type != STC_FW_IP_NONE) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ if (rule->family == STC_FW_FAMILY_V4) {
+ inet_pton(AF_INET, str, &(rule->s_ip1.Ipv4));
+ STC_LOGD("%s: [%08x]", RULE_SIP1, rule->s_ip1.Ipv4.s_addr);
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ inet_pton(AF_INET6, str, &(rule->s_ip1.Ipv6));
+ STC_LOGD("%s: [%08x:%08x:%08x:%08x]", RULE_SIP1,
+ rule->s_ip1.Ipv6.s6_addr32[0], rule->s_ip1.Ipv6.s6_addr32[1],
+ rule->s_ip1.Ipv6.s6_addr32[2], rule->s_ip1.Ipv6.s6_addr32[3]);
+ }
+ }
+
+ } else if (g_strcmp0(key, RULE_SIP2) == 0) {
+ if (rule->s_ip_type != STC_FW_IP_NONE) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ if (rule->family == STC_FW_FAMILY_V4) {
+ inet_pton(AF_INET, str, &(rule->s_ip2.Ipv4));
+ STC_LOGD("%s: [%08x]", RULE_SIP2, rule->s_ip2.Ipv4.s_addr);
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ inet_pton(AF_INET6, str, &(rule->s_ip2.Ipv6));
+ STC_LOGD("%s: [%08x:%08x:%08x:%08x]", RULE_SIP2,
+ rule->s_ip2.Ipv6.s6_addr32[0], rule->s_ip2.Ipv6.s6_addr32[1],
+ rule->s_ip2.Ipv6.s6_addr32[2], rule->s_ip2.Ipv6.s6_addr32[3]);
+ }
+ }
+
+ } else if (g_strcmp0(key, RULE_DIP1) == 0) {
+ if (rule->d_ip_type != STC_FW_IP_NONE) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ if (rule->family == STC_FW_FAMILY_V4) {
+ inet_pton(AF_INET, str, &(rule->d_ip1.Ipv4));
+ STC_LOGD("%s: [%08x]", RULE_DIP1, rule->d_ip1.Ipv4.s_addr);
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ inet_pton(AF_INET6, str, &(rule->d_ip1.Ipv6));
+ STC_LOGD("%s: [%08x:%08x:%08x:%08x]", RULE_DIP1,
+ rule->d_ip1.Ipv6.s6_addr32[0], rule->d_ip1.Ipv6.s6_addr32[1],
+ rule->d_ip1.Ipv6.s6_addr32[2], rule->d_ip1.Ipv6.s6_addr32[3]);
+ }
+ }
+
+ } else if (g_strcmp0(key, RULE_DIP2) == 0) {
+ if (rule->d_ip_type != STC_FW_IP_NONE) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ if (rule->family == STC_FW_FAMILY_V4) {
+ inet_pton(AF_INET, str, &(rule->d_ip2.Ipv4));
+ STC_LOGD("%s: [%08x]", RULE_DIP2, rule->d_ip2.Ipv4.s_addr);
+ } else if (rule->family == STC_FW_FAMILY_V6) {
+ inet_pton(AF_INET6, str, &(rule->d_ip2.Ipv6));
+ STC_LOGD("%s: [%08x:%08x:%08x:%08x]", RULE_DIP2,
+ rule->d_ip2.Ipv6.s6_addr32[0], rule->d_ip2.Ipv6.s6_addr32[1],
+ rule->d_ip2.Ipv6.s6_addr32[2], rule->d_ip2.Ipv6.s6_addr32[3]);
+ }
+ }
+
+ } else if (g_strcmp0(key, RULE_SPORT1) == 0) {
+ if (rule->s_port_type != STC_FW_PORT_NONE) {
+ rule->s_port1 = g_variant_get_uint32(value);
+ STC_LOGD("%s: [%04x]", RULE_SPORT1, rule->s_port1);
+ }
+
+ } else if (g_strcmp0(key, RULE_SPORT2) == 0) {
+ if (rule->s_port_type != STC_FW_PORT_NONE) {
+ rule->s_port2 = g_variant_get_uint32(value);
+ STC_LOGD("%s: [%04x]", RULE_SPORT2, rule->s_port2);
+ }
+
+ } else if (g_strcmp0(key, RULE_DPORT1) == 0) {
+ if (rule->d_port_type != STC_FW_PORT_NONE) {
+ rule->d_port1 = g_variant_get_uint32(value);
+ STC_LOGD("%s: [%04x]", RULE_DPORT1, rule->d_port1);
+ }
+
+ } else if (g_strcmp0(key, RULE_DPORT2) == 0) {
+ if (rule->d_port_type != STC_FW_PORT_NONE) {
+ rule->d_port2 = g_variant_get_uint32(value);
+ STC_LOGD("%s: [%04x]", RULE_DPORT2, rule->d_port2);
+ }
+
+ } else if (g_strcmp0(key, RULE_IFNAME) == 0) {
+ if (rule->direction != STC_FW_DIRECTION_NONE) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ rule->ifname = g_strdup(str);
+ STC_LOGD("%s: [%s]", RULE_IFNAME, rule->ifname);
+ }
+
+ } else if (g_strcmp0(key, RULE_TARGET) == 0) {
+ rule->target = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_TARGET, rule->target);
+
+ } else if (g_strcmp0(key, RULE_LOG_LEVEL) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_LOG) {
+ rule->log_level = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_LOG_LEVEL, rule->log_level);
+ }
+
+ } else if (g_strcmp0(key, RULE_LOG_PREFIX) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_LOG) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ rule->log_prefix = g_strdup(str);
+ STC_LOGD("%s: [%s]", RULE_LOG_PREFIX, rule->log_prefix);
+ }
+
+ } else if (g_strcmp0(key, RULE_NFLOG_GROUP) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_NFLOG) {
+ rule->nflog_group = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_NFLOG_GROUP, rule->nflog_group);
+ }
+
+ } else if (g_strcmp0(key, RULE_NFLOG_PREFIX) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_NFLOG) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ rule->nflog_prefix = g_strdup(str);
+ STC_LOGD("%s: [%s]", RULE_NFLOG_PREFIX, rule->nflog_prefix);
+ }
+
+ } else if (g_strcmp0(key, RULE_NFLOG_RANGE) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_NFLOG) {
+ rule->nflog_range = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_NFLOG_RANGE, rule->nflog_range);
+ }
+
+ } else if (g_strcmp0(key, RULE_NFLOG_THRESHOLD) == 0) {
+ if (rule->target == STC_FW_RULE_TARGET_NFLOG) {
+ rule->nflog_threshold = g_variant_get_uint16(value);
+ STC_LOGD("%s: [%u]", RULE_NFLOG_THRESHOLD, rule->nflog_threshold);
+ }
+
+ } else if (g_strcmp0(key, RULE_IDENTIFIER) == 0) {
+ guint str_length;
+ const gchar *str = g_variant_get_string(value, &str_length);
+ rule->identifier = g_strdup(str);
+ STC_LOGD("%s: [%s]", RULE_IDENTIFIER, rule->identifier);
+
+ } else if (g_strcmp0(key, RULE_KEY) == 0) {
+ rule->key = g_variant_get_uint32(value);
+ STC_LOGD("%s: [%u]", RULE_KEY, rule->key);
+
+ } else {
+ STC_LOGD("Unknown rule [%s]", key);
+ }
+}
+
+gboolean __validate_fw_rule(firewall_rule_s *rule)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ if (rule == NULL) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->chain == NULL) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->direction > STC_FW_DIRECTION_OUT) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->s_ip_type > STC_FW_IP_RANGE) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->d_ip_type > STC_FW_IP_RANGE) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->s_port_type > STC_FW_PORT_RANGE) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->d_port_type > STC_FW_PORT_RANGE) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->protocol > STC_FW_PROTOCOL_ALL) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->family > STC_FW_FAMILY_V6) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->target >= STC_FW_RULE_TARGET_MAX) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->target == STC_FW_RULE_TARGET_LOG &&
+ (rule->log_prefix == NULL ||
+ rule->log_prefix[0] == '\0')) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ if (rule->target == STC_FW_RULE_TARGET_NFLOG &&
+ (rule->nflog_prefix == NULL ||
+ rule->nflog_prefix[0] == '\0')) {
+ __STC_LOG_FUNC_EXIT__;
+ return FALSE;
+ }
+
+ __STC_LOG_FUNC_EXIT__;
+ return TRUE;
+}
+
+//LCOV_EXCL_START
+int stc_plugin_firewall_initialize(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ int ret = STC_ERROR_NONE;
+
+ g_firewalls = g_hash_table_new_full(g_str_hash,
+ g_str_equal, g_free, __fw_data_free);
+
+ ret = table_firewall_get_lock(LOCK_NAME, &g_lock_state);
+ if (ret != STC_ERROR_NONE)
+ table_firewall_insert_lock(LOCK_NAME, FIREWALL_UNLOCKED);
+
+ if (g_lock_state == FIREWALL_UNKONWN)
+ g_lock_state = FIREWALL_UNLOCKED;
+
+ table_firewall_foreach_chain(__fw_table_chain_info_cb, NULL);
+ table_firewall_foreach_rule(__fw_table_rule_info_cb, NULL);
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_deinitialize(void)
+{
+ __STC_LOG_FUNC_ENTER__;
+
+ if (g_firewalls) {
+ g_hash_table_destroy(g_firewalls);
+ g_firewalls = NULL;
+ }
+
+ __STC_LOG_FUNC_EXIT__;
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_lock(void)
+{
+ int ret = STC_ERROR_NONE;
+
+ ret = table_firewall_update_lock(LOCK_NAME, FIREWALL_LOCKED);
+ if (ret != STC_ERROR_NONE)
+ table_firewall_insert_lock(LOCK_NAME, FIREWALL_LOCKED);
+
+ g_lock_state = FIREWALL_LOCKED;
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_unlock(void)
+{
+ int ret = STC_ERROR_NONE;
+
+ ret = table_firewall_update_lock(LOCK_NAME, FIREWALL_UNLOCKED);
+ if (ret != STC_ERROR_NONE)
+ table_firewall_insert_lock(LOCK_NAME, FIREWALL_UNLOCKED);
+
+ g_lock_state = FIREWALL_UNLOCKED;
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_get_lock(int *state)
+{
+ int ret = STC_ERROR_NONE;
+
+ if (g_lock_state == FIREWALL_UNKONWN) {
+ ret = table_firewall_get_lock(LOCK_NAME, &g_lock_state);
+ if (ret != STC_ERROR_NONE)
+ table_firewall_insert_lock(LOCK_NAME, FIREWALL_UNLOCKED);
+
+ if (g_lock_state == FIREWALL_UNKONWN)
+ g_lock_state = FIREWALL_UNLOCKED;
+ }
+
+ *state = g_lock_state;
+
+ return STC_ERROR_NONE;
+}
+
+API int stc_plugin_firewall_update(void)
+{
+ __fw_chain_foreach(__fw_foreach_to_add_chain, NULL);
+ __fw_chain_foreach(__fw_foreach_to_set_rule_to_chain, NULL);
+ __fw_chain_foreach(__fw_foreach_to_set_chain, NULL);
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_add_chain(char *chain)
+{
+ int ret = STC_ERROR_NONE;
+ firewall_chain_s info;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ ret = __fw_chain_add(chain);
+ if (ret == STC_ERROR_NONE) {
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ info.priority = 0;
+ info.target = STC_FW_CHAIN_TARGET_NONE;
+ table_firewall_insert_chain(&info);
+ } else {
+ return STC_ERROR_FAIL;
+ }
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_remove_chain(char *chain)
+{
+ firewall_chain_s info;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ ret = __fw_chain_remove(chain);
+ if (ret == STC_ERROR_NONE) {
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ table_firewall_flush_chain(&info);
+ table_firewall_delete_chain(&info);
+ } else {
+ return STC_ERROR_FAIL;
+ }
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_flush_chain(char *chain)
+{
+ firewall_chain_s info;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ ret = __fw_chain_flush(chain);
+ if (ret == STC_ERROR_NONE) {
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ table_firewall_flush_chain(&info);
+ } else {
+ return STC_ERROR_FAIL;
+ }
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_get_all_chain(GVariantBuilder *builder)
+{
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ __fw_chain_foreach(__fw_chain_make_params, builder);
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_set_chain(char *chain, uint target)
+{
+ stc_fw_data_s *lookup = NULL;
+ stc_fw_data_s data;
+ firewall_chain_s info;
+ uint priority;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ lookup = __fw_chain_get(chain);
+ if (lookup == NULL)
+ return STC_ERROR_NO_DATA;
+
+ if (lookup->target != STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_FW_LOG)
+ STC_LOGE("chain is already set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ info.target = target;
+
+ ret = firewall_chain_add(&info);
+ if (ret != STC_ERROR_NONE)
+ return ret;
+
+ __fw_chain_foreach(__fw_foreach_to_set_rule_to_chain, chain);
+ ret = firewall_chain_set(&info);
+ if (ret != STC_ERROR_NONE)
+ return ret;
+
+ priority = g_chain_priority + 1;
+
+ memset(&data, 0, sizeof(stc_fw_data_s));
+ data.target = target;
+ data.priority = priority;
+
+ ret = __fw_chain_set(chain, data);
+ if (ret == STC_ERROR_NONE) {
+ info.priority = priority;
+ table_firewall_update_chain(&info);
+ g_chain_priority = priority;
+ } else {
+ return STC_ERROR_FAIL;
+ }
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_unset_chain(char *chain)
+{
+ stc_fw_data_s *lookup = NULL;
+ firewall_chain_s info;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ lookup = __fw_chain_get(chain);
+ if (lookup == NULL)
+ return STC_ERROR_NO_DATA;
+
+ if (lookup->target == STC_FW_CHAIN_TARGET_NONE) {
+ if (STC_FW_LOG)
+ STC_LOGE("chain is not set");
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ memset(&info, 0, sizeof(firewall_chain_s));
+ info.chain = chain;
+ info.target = lookup->target;
+
+ ret = firewall_chain_unset(&info);
+ if (ret != STC_ERROR_NONE)
+ return ret;
+
+ ret = firewall_chain_remove(&info);
+ if (ret != STC_ERROR_NONE)
+ return ret;
+
+ ret = __fw_chain_unset(chain);
+ if (ret == STC_ERROR_NONE) {
+ info.target = STC_FW_CHAIN_TARGET_NONE;
+ info.priority = 0;
+ table_firewall_update_chain(&info);
+ } else {
+ return STC_ERROR_FAIL;
+ }
+
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_add_rule(GVariant *params)
+{
+ GVariantIter *iter = NULL;
+ firewall_rule_s *rule;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ rule = MALLOC0(firewall_rule_s, 1);
+ if (!rule)
+ return STC_ERROR_OUT_OF_MEMORY;
+
+ memset(rule, 0, sizeof(firewall_rule_s));
+
+ g_variant_get(params, "a{sv}", &iter);
+ if (iter != NULL) {
+ stc_manager_gdbus_dict_foreach(iter,
+ __fw_rule_extract,
+ rule);
+ g_variant_iter_free(iter);
+ }
+
+ if (__validate_fw_rule(rule) == FALSE) {
+ __fw_rule_free(rule);
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ ret = __fw_rule_add(rule);
+ if (ret == STC_ERROR_NONE) {
+ table_firewall_insert_rule(rule);
+ } else {
+ __fw_rule_free(rule);
+ return ret;
+ }
+
+ __fw_rule_free(rule);
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_remove_rule(GVariant *params)
+{
+ GVariantIter *iter = NULL;
+ firewall_rule_s *rule;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ rule = MALLOC0(firewall_rule_s, 1);
+ if (!rule)
+ return STC_ERROR_OUT_OF_MEMORY;
+
+ memset(rule, 0, sizeof(firewall_rule_s));
+
+ g_variant_get(params, "a{sv}", &iter);
+ if (iter != NULL) {
+ stc_manager_gdbus_dict_foreach(iter,
+ __fw_rule_extract,
+ rule);
+ g_variant_iter_free(iter);
+ }
+
+ if (__validate_fw_rule(rule) == FALSE) {
+ __fw_rule_free(rule);
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ ret = __fw_rule_remove(rule);
+ if (ret == STC_ERROR_NONE) {
+ table_firewall_delete_rule(rule);
+ } else {
+ __fw_rule_free(rule);
+ return ret;
+ }
+
+ __fw_rule_free(rule);
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_update_rule(GVariant *params)
+{
+ GVariantIter *iter = NULL;
+ firewall_rule_s *rule;
+ guint key;
+ int ret = STC_ERROR_NONE;
+
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ rule = MALLOC0(firewall_rule_s, 1);
+ if (!rule)
+ return STC_ERROR_OUT_OF_MEMORY;
+
+ memset(rule, 0, sizeof(firewall_rule_s));
+
+ g_variant_get(params, "a{sv}", &iter);
+ if (iter != NULL) {
+ stc_manager_gdbus_dict_foreach(iter,
+ __fw_rule_extract,
+ rule);
+ g_variant_iter_free(iter);
+ }
+
+ if (__validate_fw_rule(rule) == FALSE) {
+ __fw_rule_free(rule);
+ return STC_ERROR_INVALID_PARAMETER;
+ }
+
+ key = rule->key;
+ ret = __fw_rule_update(rule);
+ if (ret == STC_ERROR_NONE) {
+ table_firewall_update_rule(rule, key);
+ } else {
+ __fw_rule_free(rule);
+ return ret;
+ }
+
+ __fw_rule_free(rule);
+ return STC_ERROR_NONE;
+}
+
+int stc_plugin_firewall_get_all_rule(GVariantBuilder *builder)
+{
+ STC_FIREWALL_CHECK_LOCK_STATE();
+
+ __fw_chain_foreach(__fw_foreach_to_make_rule_param, builder);
+ __fw_chain_foreach(__fw_foreach_to_print_rule, NULL);
+
+ return STC_ERROR_NONE;
+}
+
+API stc_plugin_firewall_s stc_plugin_firewall = {
+ .initialize_plugin =
+ stc_plugin_firewall_initialize,
+ .deinitialize_plugin =
+ stc_plugin_firewall_deinitialize,
+ .lock_firewall =
+ stc_plugin_firewall_lock,
+ .unlock_firewall =
+ stc_plugin_firewall_unlock,
+ .get_lock_firewall =
+ stc_plugin_firewall_get_lock,
+ .update_firewall =
+ stc_plugin_firewall_update,
+ .add_chain =
+ stc_plugin_firewall_add_chain,
+ .remove_chain =
+ stc_plugin_firewall_remove_chain,
+ .flush_chain =
+ stc_plugin_firewall_flush_chain,
+ .get_all_chain =
+ stc_plugin_firewall_get_all_chain,
+ .set_chain =
+ stc_plugin_firewall_set_chain,
+ .unset_chain =
+ stc_plugin_firewall_unset_chain,
+ .add_rule =
+ stc_plugin_firewall_add_rule,
+ .remove_rule =
+ stc_plugin_firewall_remove_rule,
+ .update_rule =
+ stc_plugin_firewall_update_rule,
+ .get_all_rule =
+ stc_plugin_firewall_get_all_rule
+};
+//LCOV_EXCL_STOP