--- /dev/null
+/*
+ * Copyright (c) 2016 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-manager-gdbus.h"
+#include "helper-iptables.h"
+
+#define STC_IPTABLES_DBUS_SERVICE "net.stc.iptables"
+#define STC_IPTABLES_DBUS_RULE_INTERFACE STC_IPTABLES_DBUS_SERVICE ".rule"
+#define STC_IPTABLES_DBUS_CHAIN_INTERFACE STC_IPTABLES_DBUS_SERVICE ".chain"
+#define STC_IPTABLES_DBUS_RULE_PATH "/net/stc/iptables/rule"
+#define STC_IPTABLES_DBUS_CHAIN_PATH "/net/stc/iptables/chain"
+#define STC_IPTABLES_DBUS_METHOD_IPT_ADD_CHAIN "IptAddChain"
+#define STC_IPTABLES_DBUS_METHOD_IPT_REMOVE_CHAIN "IptRemoveChain"
+#define STC_IPTABLES_DBUS_METHOD_IP6T_ADD_CHAIN "Ip6tAddChain"
+#define STC_IPTABLES_DBUS_METHOD_IP6T_REMOVE_CHAIN "Ip6tRemoveChain"
+#define STC_IPTABLES_DBUS_METHOD_IPT_ADD_RULE "IptAddRule"
+#define STC_IPTABLES_DBUS_METHOD_IPT_REMOVE_RULE "IptRemoveRule"
+#define STC_IPTABLES_DBUS_METHOD_IP6T_ADD_RULE "Ip6tAddRule"
+#define STC_IPTABLES_DBUS_METHOD_IP6T_REMOVE_RULE "Ip6tRemoveRule"
+
+#define RULE_CHAIN "chain"
+#define RULE_TYPE "type"
+#define RULE_IFNAME "ifname"
+#define RULE_CGROUP "cgroup"
+#define RULE_NFACCT "nfacct"
+#define RULE_TARGET "target"
+
+static void __add_rule_info_to_builder(GVariantBuilder *builder,
+ iptables_rule_s *rule)
+{
+ if (builder == NULL || rule == NULL)
+ return;
+
+ g_variant_builder_add(builder, "{sv}", RULE_CHAIN,
+ g_variant_new_string(rule->chain));
+
+ g_variant_builder_add(builder, "{sv}", RULE_TYPE,
+ g_variant_new_uint32(rule->direction));
+
+ if (rule->ifname)
+ g_variant_builder_add(builder, "{sv}", RULE_IFNAME,
+ g_variant_new_string(rule->ifname));
+
+ if (rule->classid > 0)
+ g_variant_builder_add(builder, "{sv}", RULE_CGROUP,
+ g_variant_new_uint32(rule->classid));
+
+ if (rule->nfacct_name)
+ g_variant_builder_add(builder, "{sv}", RULE_NFACCT,
+ g_variant_new_string(rule->nfacct_name));
+
+ if (rule->target)
+ g_variant_builder_add(builder, "{sv}", RULE_TARGET,
+ g_variant_new_string(rule->target));
+
+}
+
+static int __iptables_rule_add(GDBusConnection *connection,
+ iptables_rule_s *rule)
+{
+ int result = 0;
+ GVariantBuilder *builder = NULL;
+ GVariant *params = NULL;
+ GVariant *message = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ __add_rule_info_to_builder(builder, rule);
+ params = g_variant_new("(a{sv})", builder);
+ g_variant_builder_unref(builder);
+
+ message = stc_manager_gdbus_call_sync(connection,
+ STC_IPTABLES_DBUS_SERVICE,
+ STC_IPTABLES_DBUS_RULE_PATH,
+ STC_IPTABLES_DBUS_RULE_INTERFACE,
+ STC_IPTABLES_DBUS_METHOD_IPT_ADD_RULE,
+ params);
+
+ if (message == NULL) {
+ STC_LOGE("Failed to invoke dbus method");
+ return STC_ERROR_FAIL;
+ }
+
+ g_variant_get(message, "(i)", &result);
+ STC_LOGD("Successfully Add Rule [%d]", result);
+ g_variant_unref(message);
+
+ return STC_ERROR_NONE;
+}
+
+static int __iptables_rule_remove(GDBusConnection *connection,
+ iptables_rule_s *rule)
+{
+ int result = 0;
+ GVariantBuilder *builder = NULL;
+ GVariant *params = NULL;
+ GVariant *message = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ __add_rule_info_to_builder(builder, rule);
+ params = g_variant_new("(a{sv})", builder);
+ g_variant_builder_unref(builder);
+
+ message = stc_manager_gdbus_call_sync(connection,
+ STC_IPTABLES_DBUS_SERVICE,
+ STC_IPTABLES_DBUS_RULE_PATH,
+ STC_IPTABLES_DBUS_RULE_INTERFACE,
+ STC_IPTABLES_DBUS_METHOD_IPT_REMOVE_RULE,
+ params);
+
+ if (message == NULL) {
+ STC_LOGE("Failed to invoke dbus method");
+ return STC_ERROR_FAIL;
+ }
+
+ g_variant_get(message, "(i)", &result);
+ STC_LOGD("Successfully Remove Rule [%d]", result);
+ g_variant_unref(message);
+
+ return STC_ERROR_NONE;
+}
+
+static int __ip6tables_rule_add(GDBusConnection *connection,
+ iptables_rule_s *rule)
+{
+ int result = 0;
+ GVariantBuilder *builder = NULL;
+ GVariant *params = NULL;
+ GVariant *message = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ __add_rule_info_to_builder(builder, rule);
+ params = g_variant_new("(a{sv})", builder);
+ g_variant_builder_unref(builder);
+
+ message = stc_manager_gdbus_call_sync(connection,
+ STC_IPTABLES_DBUS_SERVICE,
+ STC_IPTABLES_DBUS_RULE_PATH,
+ STC_IPTABLES_DBUS_RULE_INTERFACE,
+ STC_IPTABLES_DBUS_METHOD_IP6T_ADD_RULE,
+ params);
+
+ if (message == NULL) {
+ STC_LOGE("Failed to invoke dbus method");
+ return STC_ERROR_FAIL;
+ }
+
+ g_variant_get(message, "(i)", &result);
+ STC_LOGD("Successfully Add 6 Rule [%d]", result);
+ g_variant_unref(message);
+
+ return STC_ERROR_NONE;
+}
+
+static int __ip6tables_rule_remove(GDBusConnection *connection,
+ iptables_rule_s *rule)
+{
+ int result = 0;
+ GVariantBuilder *builder = NULL;
+ GVariant *params = NULL;
+ GVariant *message = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ __add_rule_info_to_builder(builder, rule);
+ params = g_variant_new("(a{sv})", builder);
+ g_variant_builder_unref(builder);
+
+ message = stc_manager_gdbus_call_sync(connection,
+ STC_IPTABLES_DBUS_SERVICE,
+ STC_IPTABLES_DBUS_RULE_PATH,
+ STC_IPTABLES_DBUS_RULE_INTERFACE,
+ STC_IPTABLES_DBUS_METHOD_IP6T_REMOVE_RULE,
+ params);
+
+ if (message == NULL) {
+ STC_LOGE("Failed to invoke dbus method");
+ return STC_ERROR_FAIL;
+ }
+
+ g_variant_get(message, "(i)", &result);
+ STC_LOGD("Successfully Remove 6 Rule [%d]", result);
+ g_variant_unref(message);
+
+ return STC_ERROR_NONE;
+}
+
+stc_error_e iptables_add(iptables_rule_s *rule)
+{
+ stc_error_e ret = STC_ERROR_NONE;
+ stc_s *stc = stc_get_manager();
+
+ if (!stc || !stc->connection)
+ return STC_ERROR_INVALID_PARAMETER;
+
+ ret = __iptables_rule_add(stc->connection, rule);
+ if (ret != STC_ERROR_NONE)
+ goto done;
+
+ ret = __ip6tables_rule_add(stc->connection, rule);
+done:
+ return ret;
+}
+
+stc_error_e iptables_remove(iptables_rule_s *rule)
+{
+ stc_error_e ret = STC_ERROR_NONE;
+ stc_s *stc = stc_get_manager();
+
+ if (!stc || !stc->connection)
+ return STC_ERROR_INVALID_PARAMETER;
+
+ ret = __iptables_rule_remove(stc->connection, rule);
+ if (ret != STC_ERROR_NONE)
+ goto done;
+
+ ret = __ip6tables_rule_remove(stc->connection, rule);
+done:
+ return ret;
+}
#include "counter.h"
#include "helper-nfacct-rule.h"
+#include "helper-iptables.h"
#include "configure_stub.h"
#define INSERT "-I"
#define NFACCT_NAME_MOD " -m nfacct --nfacct-name %s"
-#define REJECT_RULE " -j REJECT"
-#define ACCEPT_RULE " -j ACCEPT"
+#define REJECT_RULE "REJECT"
+#define ACCEPT_RULE "ACCEPT"
#define OUT_RULE "OUTPUT"
#define IN_RULE "INPUT"
#define FORWARD_RULE "FORWARD"
return &command;
}
-static unsigned int get_args_number(const char *cmd_buf)
-{
- char *str;
- unsigned int count = 0;
-
- for (str = (char *)cmd_buf; *str != '\0'; ++str) {
- if (*str == ' ')
- ++count;
- }
- return count;
-}
-
-static void wait_for_rule_cmd(pid_t pid)
-{
- int status;
- pid_t ret_pid;
-
- if (!pid || pid == -1) {
- STC_LOGD("no need to wait");
- return;
- }
-
- ret_pid = waitpid(pid, &status, 0);
- if (ret_pid < 0) {
- char buf[BUF_SIZE_FOR_ERR] = { 0 };
- STC_LOGD("can't wait for a pid %d %d %s", pid, status,
- strerror_r(errno, buf, BUF_SIZE_FOR_ERR));
- }
-}
-
-stc_error_e exec_iptables_cmd(const char *cmd_buf, pid_t *cmd_pid)
-{
- const size_t args_number = get_args_number(cmd_buf);
- *cmd_pid = 0;
-
- ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
-
- pid_t pid = fork();
-
- if (pid == 0) {
- char *cmd;
- unsigned int i;
- char *args[args_number + 2];
- int ret;
- char *save_ptr = NULL;
-
- if (STC_DEBUG_LOG)
- STC_LOGD("executing iptables cmd %s in forked process", cmd_buf);
-
- args[0] = "iptables";
- cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
- if (cmd == NULL) {
- STC_LOGE("no arguments");
- exit(-EINVAL);
- }
-
- for (i = 1; i <= args_number; ++i)
- args[i] = strtok_r(NULL, " ", &save_ptr);
-
- args[i] = NULL;
-
- ret = execv(cmd, args);
- if (ret) {
- char buf[BUF_SIZE_FOR_ERR] = { 0 };
- STC_LOGE("Can't execute %s: %s",
- cmd_buf, strerror_r(errno, buf,
- BUF_SIZE_FOR_ERR));
- }
- exit(ret);
- }
-
- *cmd_pid = pid;
- return STC_ERROR_NONE;
-}
-
-stc_error_e exec_ip6tables_cmd(const char *cmd_buf, pid_t *cmd_pid)
-{
- const size_t args_number = get_args_number(cmd_buf);
- *cmd_pid = 0;
-
- ret_value_msg_if(args_number == 0, STC_ERROR_FAIL, "no arguments");
-
- pid_t pid = fork();
-
- if (pid == 0) {
- char *cmd;
- unsigned int i;
- char *args[args_number + 2];
- int ret;
- char *save_ptr = NULL;
-
- if (STC_DEBUG_LOG)
- STC_LOGD("executing ip6tables cmd %s in forked process", cmd_buf);
-
- args[0] = "ip6tables";
- cmd = strtok_r((char *)cmd_buf, " ", &save_ptr);
- if (cmd == NULL) {
- STC_LOGE("no arguments");
- exit(-EINVAL);
- }
-
- for (i = 1; i <= args_number; ++i)
- args[i] = strtok_r(NULL, " ", &save_ptr);
-
- args[i] = NULL;
-
- ret = execv(cmd, args);
- if (ret) {
- char buf[BUF_SIZE_FOR_ERR] = { 0 };
- STC_LOGE("Can't execute %s: %s",
- cmd_buf, strerror_r(errno, buf,
- BUF_SIZE_FOR_ERR));
- }
- exit(ret);
- }
-
- *cmd_pid = pid;
- return STC_ERROR_NONE;
-}
-
-static char *choose_iftype_name(nfacct_rule_s *rule)
-{
- return strlen(rule->ifname) != 0 ? rule->ifname :
- get_iftype_name(rule->iftype);
-}
-
-static stc_error_e exec_iface_cmd(const char *pattern, const char *cmd,
- const char *chain, const char *nfacct,
- const char *jump, char *iftype_name,
- pid_t *pid, nfacct_rule_iptype iptype)
-{
- char block_buf[MAX_PATH_LENGTH];
- int ret;
- const char *iptables_type = IPTABLES;
-
- ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
- "Invalid network interface name argument");
-
- if (iptype == NFACCT_TYPE_IPV6)
- iptables_type = IP6TABLES;
-
- ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
- cmd, chain, iftype_name, nfacct, jump);
- ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
- "Not enough buffer");
-
- if (iptype == NFACCT_TYPE_IPV6)
- exec_ip6tables_cmd(block_buf, pid);
- else
- exec_iptables_cmd(block_buf, pid);
-
- wait_for_rule_cmd(*pid);
-
- return STC_ERROR_NONE;
-}
-
-static stc_error_e exec_app_cmd(const char *pattern, const char *cmd,
- const char *nfacct, const char *jump,
- const uint32_t classid, char *iftype_name,
- pid_t *pid, nfacct_rule_iptype iptype)
-{
- char block_buf[MAX_PATH_LENGTH];
- int ret;
- const char *iptables_type = IPTABLES;
-
- ret_value_msg_if(iftype_name == NULL, STC_ERROR_FAIL,
- "Invalid network interface name argument");
-
- if (iptype == NFACCT_TYPE_IPV6)
- iptables_type = IP6TABLES;
-
- ret = snprintf(block_buf, sizeof(block_buf), pattern, iptables_type,
- cmd, iftype_name, classid, nfacct, jump);
- ret_value_msg_if(ret > sizeof(block_buf), STC_ERROR_FAIL,
- "Not enough buffer");
-
- if (iptype == NFACCT_TYPE_IPV6)
- exec_ip6tables_cmd(block_buf, pid);
- else
- exec_iptables_cmd(block_buf, pid);
-
- wait_for_rule_cmd(*pid);
-
- return STC_ERROR_NONE;
-}
-
static char *get_iptables_cmd(const nfacct_rule_action action)
{
if (action == NFACCT_ACTION_APPEND)
return IN_RULE;
else if (iotype == NFACCT_COUNTER_OUT)
return OUT_RULE;
+ else if (iotype == NFACCT_COUNTER_FORWARD)
+ return FORWARD_RULE;
return "";
}
return "";
}
+static char *choose_iftype_name(nfacct_rule_s *rule)
+{
+ return strlen(rule->ifname) != 0 ? rule->ifname :
+ get_iftype_name(rule->iftype);
+}
+
+static stc_error_e exec_iptables_cmd(nfacct_rule_s *rule)
+{
+ stc_error_e ret = STC_ERROR_NONE;
+ iptables_rule_s iptables_rule;
+ memset(&iptables_rule, 0, sizeof(iptables_rule_s));
+
+ iptables_rule.nfacct_name = g_strdup(rule->name);
+ iptables_rule.ifname = g_strdup(rule->ifname);
+ iptables_rule.target = g_strdup(get_iptables_jump(rule->jump));
+ iptables_rule.chain = g_strdup(get_iptables_chain(rule->iotype));
+ iptables_rule.classid = rule->classid;
+ iptables_rule.direction = (rule->iotype & NFACCT_COUNTER_IN) ? 0 : 1;
+
+ if (rule->action == NFACCT_ACTION_DELETE) {
+ /* delete interface rule */
+ ret = iptables_remove(&iptables_rule);
+ } else {
+ /* add interface rule */
+ ret = iptables_add(&iptables_rule);
+ }
+
+ g_free(iptables_rule.nfacct_name);
+ g_free(iptables_rule.ifname);
+ g_free(iptables_rule.target);
+ g_free(iptables_rule.chain);
+
+ return ret;
+}
+
static stc_error_e produce_app_rule(nfacct_rule_s *rule)
{
if (rule == NULL)
char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
3*MAX_DEC_SIZE(int) + 4];
stc_error_e ret = STC_ERROR_NONE;
- pid_t pid = 0;
/* income part */
if (rule->iotype & NFACCT_COUNTER_IN) {
ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
STC_ERROR_FAIL, "Not enought buffer");
- ret = exec_app_cmd(RULE_APP_IN, set_cmd, nfacct_buf, jump_cmd,
- rule->classid, choose_iftype_name(rule),
- &pid, rule->iptype);
+ ret = exec_iptables_cmd(rule);
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set conditional block for ingress"
" traffic, for classid %u, cmd %s, j %s",
ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
STC_ERROR_FAIL, "Not enought buffer");
- ret = exec_app_cmd(RULE_APP_OUT, set_cmd, nfacct_buf, jump_cmd,
- rule->classid, choose_iftype_name(rule),
- &pid, rule->iptype);
+ ret = exec_iptables_cmd(rule);
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set conditional block for engress"
" traffic, for classid %u, cmd %s, j %s",
rule->classid, set_cmd, jump_cmd);
+
if (rule->action == NFACCT_ACTION_DELETE) {
rule->iptables_rule = nfacct_send_del;
/* not effective, it's better to replace
char nfacct_buf[sizeof(NFACCT_NAME_MOD) +
3*MAX_DEC_SIZE(int) + 4];
stc_error_e ret;
- pid_t pid = 0;
+
+ rule->classid = 0;
if (rule->iotype & NFACCT_COUNTER_IN) {
/* income part */
ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
STC_ERROR_FAIL, "Not enought buffer");
- ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
- get_iptables_chain(rule->iotype),
- nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid,
- rule->iptype);
+ ret = exec_iptables_cmd(rule);
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set conditional block for ingress"
" traffic, for iftype %d, cmd %s, j %s",
if (rule->intend == NFACCT_WARN ||
rule->intend == NFACCT_BLOCK) {
/* RULE_IFACE_OUT is not a misprint here */
- ret = exec_iface_cmd(RULE_IFACE_IN, set_cmd,
- FORWARD_RULE, nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid,
- rule->iptype);
+ nfacct_rule_direction temp_iotype = rule->iotype;
+
+ rule->iotype = NFACCT_COUNTER_FORWARD;
+ ret = exec_iptables_cmd(rule);
+ rule->iotype = temp_iotype;
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set forward rule for ingress "
"traffic, for iftype %d, cmd %s, j %s",
ret_value_msg_if(ret > sizeof(nfacct_buf) || ret < 0,
STC_ERROR_FAIL, "Not enough buffer");
- ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd, OUT_RULE,
- nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid,
- rule->iptype);
+ ret = exec_iptables_cmd(rule);
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set conditional block for "
"engress traffic, for iftype %d, cmd %s, j %s",
rule->iftype, set_cmd, jump_cmd);
+
/* for tethering */
if (rule->intend == NFACCT_WARN ||
rule->intend == NFACCT_BLOCK) {
- ret = exec_iface_cmd(RULE_IFACE_OUT, set_cmd,
- FORWARD_RULE, nfacct_buf, jump_cmd,
- choose_iftype_name(rule), &pid,
- rule->iptype);
+ nfacct_rule_direction temp_iotype = rule->iotype;
+
+ rule->iotype = NFACCT_COUNTER_OUT;
+ ret = exec_iptables_cmd(rule);
+ rule->iotype = temp_iotype;
ret_value_msg_if(ret != STC_ERROR_NONE, STC_ERROR_FAIL,
"Can't set forward rule for engress "
"traffic, for iftype %d, cmd %s, j %s",