--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT("capi-vpn-service-pkg")
+
+############################# cmake packages ##################################
+
+INCLUDE(FindPkgConfig)
+
+############################# compiler flags ##################################
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX ${PREFIX}/bin)
+SET(LIBDIR ${PREFIX}/lib)
+SET(INCLUDEDIR ${PREFIX}/include)
+
+# If supported for the target machine, emit position-independent code,suitable
+# for dynamic linking and avoiding any limit on the size of the global offset
+# table. This option makes a difference on the m68k, PowerPC and SPARC.
+# (BJ: our ARM too?)
+ADD_DEFINITIONS("-fPIC")
+
+# Set compiler warning flags
+
+#ADD_DEFINITIONS("-Werror") # Make all warnings into errors.
+ADD_DEFINITIONS("-Wall") # Generate all warnings
+ADD_DEFINITIONS("-Wextra") # Generate even more extra warnings
+
+STRING(REGEX MATCH "([^.]*)" API_VERSION "${VERSION}")
+ADD_DEFINITIONS("-DAPI_VERSION=\"$(API_VERSION)\"")
+ADD_DEFINITIONS("-DSMACK_ENABLED")
+
+IF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+ ADD_DEFINITIONS("-DTIZEN_DEBUG_ENABLE")
+ ADD_DEFINITIONS("-DBUILD_TYPE_DEBUG")
+ENDIF (CMAKE_BUILD_TYPE MATCHES "DEBUG")
+
+ADD_SUBDIRECTORY(framework)
+ADD_SUBDIRECTORY(daemon)
+ADD_SUBDIRECTORY(test)
+
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME vpnsvc-daemon)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(DAEMON_DIR "${CMAKE_SOURCE_DIR}/daemon")
+SET(VERSION 0.1)
+
+SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-package-manager")
+SET(pc_requires "capi-base-common")
+
+SET(SRCS
+ src/vpnsvc.c
+ src/vpndbus.c
+ src/vpn_service_daemon.c
+ src/vpn_service_daemon_main.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/framework/include
+ ${CMAKE_SOURCE_DIR}/daemon/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -I${DAEMON_DIR}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib -pie")
+
+ADD_CUSTOM_COMMAND(
+ WORKING_DIRECTORY
+ OUTPUT ${DAEMON_DIR}/generated-code.c
+ COMMAND gdbus-codegen --interface-prefix org.tizen.
+ --generate-c-code generated-code
+ --c-generate-object-manager
+ --generate-docbook generated-code-docs
+ ${DAEMON_DIR}/interfaces/org.tizen.vpnsvc.xml
+ COMMENT "Generating GDBus .c/.h")
+
+ADD_EXECUTABLE(${PACKAGE_NAME} ${SRCS} ${DAEMON_DIR}/generated-code.c)
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} -lrt -ldl)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION bin)
+
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__
+#define __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__
+
+#include "capi_vpn_service_private.h"
+
+int vpn_daemon_init(const char* tun_name, size_t tun_name_len, int fd, vpnsvc_tun_s *handle_s);
+int vpn_daemon_deinit(const char* dev_name);
+int vpn_daemon_protect(int socket, const char* dev_name);
+int vpn_daemon_up(int tun_index, const char* local_ip, const char* remote_ip,
+ const struct vpnsvc_route* routes, size_t nr_routes,
+ char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt,
+ const char* dns_suffix, const unsigned int mtu);
+int vpn_daemon_down(int tun_index);
+int vpn_daemon_block_networks(const struct vpnsvc_route* nets_vpn, size_t nr_nets_vpn,
+ const struct vpnsvc_route* nets_orig, size_t nr_nets_orig);
+int vpn_daemon_unblock_networks(void);
+
+#endif /* __TIZEN_CAPI_VPN_SERVICE_DAEMON_H__ */
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __VPNSERVICE_VPNDBUS_H__
+#define __VPNSERVICE_VPNDBUS_H__
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VPNSERVICE_SERVICE "org.tizen.vpnsvc"
+#define VPNSERVICE_INTERFACE "org.tizen.vpnsvc"
+#define VPNSERVICE_PATH "/org/tizen/vpnsvc"
+
+typedef void (*vpnsvc_got_name_cb)(void);
+
+GDBusObjectManagerServer *vpnsvc_get_vpn_manager(void);
+GDBusConnection *vpnsvc_gdbus_get_connection(void);
+GCancellable *vpnsvc_gdbus_get_gdbus_cancellable(void);
+void vpnsvc_gdbus_pending_call_ref(void);
+void vpnsvc_gdbus_pending_call_unref(void);
+int vpnsvc_create_gdbus_call(GDBusConnection *conn);
+
+gboolean vpnsvc_invoke_dbus_method_nonblock(const char *dest, const char *path,
+ const char *interface_name, const char *method, GVariant *params,
+ GAsyncReadyCallback notify_func);
+GVariant *vpnsvc_invoke_dbus_method(const char *dest, const char *path,
+ const char *interface_name, const char *method,
+ GVariant *params);
+
+int vpnsvc_setup_gdbus(vpnsvc_got_name_cb cb);
+void vpnsvc_cleanup_gdbus(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VPNSERVICE_VPNDBUS_H__ */
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __VPNSERVICE_VPNSVC_H__
+#define __VPNSERVICE_VPNSVC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include "generated-code.h"
+
+void vpnsvc_create_and_init(void);
+Vpnsvc *get_vpnsvc_object(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __VPNSERVICE_VPNSVC_H__ */
--- /dev/null
+<node name='/org/tizen/vpnsvc'>
+ <interface name='org.tizen.vpnsvc'>
+ <method name='vpn_init'>
+ <arg type='s' name='tun_name' direction='in'/>
+ <arg type='u' name='tun_name_len' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ <arg type='i' name='h_index' direction='out'/>
+ <arg type='s' name='h_name' direction='out'/>
+ </method>
+ <method name='vpn_deinit'>
+ <arg type='s' name='dev_name' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ <method name='vpn_protect'>
+ <arg type='s' name='dev_name' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ <method name='vpn_up'>
+ <arg type='i' name='tun_index' direction='in'/>
+ <arg type='s' name='local_ip' direction='in'/>
+ <arg type='s' name='remote_ip' direction='in'/>
+ <arg type='v' name='routes' direction='in'/>
+ <arg type='u' name='nr_routes' direction='in'/>
+ <arg type='v' name='dns_servers' direction='in'/>
+ <arg type='u' name='nr_dns' direction='in'/>
+ <arg type='s' name='dns_suffix' direction='in'/>
+ <arg type='u' name='mtu' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ <method name='vpn_down'>
+ <arg type='i' name='tun_index' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ <method name='vpn_block_networks'>
+ <arg type='v' name='nets_vpn' direction='in'/>
+ <arg type='u' name='nr_nets_vpn' direction='in'/>
+ <arg type='v' name='nets_orig' direction='in'/>
+ <arg type='u' name='nr_nets_orig' direction='in'/>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ <method name='vpn_unblock_networks'>
+ <arg type='i' name='result' direction='out'/>
+ </method>
+ </interface>
+</node>
+
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <net/route.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+#include "vpn_service_daemon.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+#define CONNMAN_SERVICE "net.connman"
+#define CONNMAN_INTERFACE_MANAGER "net.connman.Manager"
+#define CONNMAN_INTERFACE_SERVICE "net.connman.Service"
+
+
+/* for iptables */
+static char iptables_cmd[] = "/usr/sbin/iptables";
+static char iptables_filter_prefix[] = "CAPI_VPN_SERVICE_";
+static char iptables_filter_out[] = "OUTPUT";
+static char iptables_filter_in[] = "INPUT";
+static char iptables_filter_interface_wlan[] = "wlan0";
+/* static char iptables_register_fmt[] = "%s -N %s%s -w;" "%s -F %s%s -w;" "%s -A %s%s -j RETURN -w;" "%s -I %s -j %s%s -w;"; */
+static char iptables_register_fmt[] = "%s -N %s%s -w;" "%s -F %s%s -w;" "%s -A %s%s -j DROP -w;" "%s -A %s%s -j RETURN -w;" "%s -I %s -j %s%s -w;";
+static char iptables_unregister_fmt[] = "%s -D %s -j %s%s -w;" "%s -F %s%s -w;" "%s -X %s%s -w;";
+static char iptables_rule_fmt[] = "%s -%c %s%s -%c %s/%d -j ACCEPT -w;";
+static char iptables_rule_with_interface_fmt[] = "%s -%c %s%s -%c %s -%c %s/%d -j ACCEPT -w;";
+/*static char iptables_usage_fmt[] = "%s -L %s%s -n -v -w;";*/
+
+typedef unsigned long int ipv4; /* Declare variable type for ipv4 net address. */
+
+static GDBusConnection *global_connection = NULL;
+
+static ipv4 make_mask(int prefix)
+{
+ ipv4 mask = 0;
+ int i = 0;
+
+ for (i = prefix; i > 0; i--)
+ mask += (ipv4) (1 << (32 - i));
+ return mask;
+}
+
+static in_addr_t host2net(ipv4 host)
+{
+ in_addr_t net;
+
+ net = 0;
+
+ net |= (host & 0x000000FF) << 24;
+ net |= (host & 0x0000FF00) << 8;
+ net |= (host & 0x00FF0000) >> 8;
+ net |= (host & 0xFF000000) >> 24;
+
+ return net;
+}
+
+static int add_routes(char* if_name, const struct vpnsvc_route* routes, size_t nr_routes)
+{
+ struct rtentry rt;
+ struct sockaddr_in addr;
+ int sk;
+ unsigned int i = 0;
+
+ LOGD("Enter add_routes");
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ LOGE("socket failed : %s", strerror(errno));
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ for (i = 0; i < nr_routes; i++) {
+ memset(&rt, 0, sizeof(rt));
+ rt.rt_flags = RTF_UP;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(routes[i].dest);
+ memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
+
+ /* set mask using by prefix length */
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_addr.s_addr = host2net(make_mask(routes[i].prefix));
+ memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
+
+ rt.rt_dev = if_name;
+
+ if (ioctl(sk, SIOCADDRT, &rt) < 0) {
+ LOGE("ioctl SIOCADDRT failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+ }
+
+ close(sk);
+
+ return VPNSVC_ERROR_NONE;
+}
+
+static void connman_connection_open(void)
+{
+ if (global_connection == NULL) {
+ GError *error = NULL;
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ g_type_init();
+#endif
+
+ global_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (global_connection == NULL) {
+ if (error != NULL) {
+ LOGE("Error connman connection open: %s", error->message);
+ g_error_free(error);
+ }
+ }
+ }
+}
+
+static void connman_connection_close(GDBusConnection *connection)
+{
+ if (connection)
+ g_object_unref(connection);
+}
+
+static GVariant *connman_method_call(
+ GDBusConnection *connection, char *service, char *path,
+ char *interface, char *method, GVariant *params)
+{
+ GError *error = NULL;
+ GVariant *message = NULL;
+
+ message = g_dbus_connection_call_sync(
+ connection, service, path, interface, method, params,
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+
+ if (message == NULL) {
+ if (error != NULL) {
+ LOGE("error: g_dbus_connection_call_sync [%d: %s]", error->code, error->message);
+ g_error_free(error);
+ } else {
+ LOGE("error: g_dbus_connection_call_sync\n");
+ }
+ }
+
+ return message;
+}
+
+static char *connman_default_profile(GDBusConnection *connection)
+{
+ gchar *key = NULL;
+ GVariantIter *value = NULL;
+ GVariant *message = NULL;
+ GVariantIter *iter = NULL;
+ char *profile = NULL;
+
+ message = connman_method_call(connection, CONNMAN_SERVICE, "/",
+ CONNMAN_INTERFACE_MANAGER, "GetServices", NULL);
+
+ if (message) {
+ g_variant_get(message, "(a(oa{sv}))", &iter);
+ while (g_variant_iter_loop(iter, "(oa{sv})", &key, &value)) {
+ profile = strdup(key);
+ break;
+ }
+
+ if (value)
+ g_variant_iter_free(value);
+ if (key)
+ g_free(key);
+
+ g_variant_iter_free(iter);
+ g_variant_unref(message);
+ }
+
+ return profile;
+}
+
+static char *connman_get_items(GDBusConnection *connection, char *profile, const char *keystr)
+{
+ GVariant *message = NULL;
+ GVariantIter *iter = NULL;
+ GVariantIter *next = NULL;
+ gchar *obj = NULL;
+ char *items = NULL;
+
+ message = connman_method_call(connection, CONNMAN_SERVICE, "/",
+ CONNMAN_INTERFACE_MANAGER, "GetServices", NULL);
+
+ if (message) {
+ g_variant_get(message, "(a(oa{sv}))", &iter);
+ while (g_variant_iter_loop(iter, "(oa{sv})", &obj, &next)) {
+ if (strcmp(obj, profile) == 0) {
+ GVariant *var;
+ gchar *key;
+
+ while (g_variant_iter_loop(next, "{sv}", &key, &var)) {
+ if (g_strcmp0(key, keystr) == 0) {
+ GVariantIter *iter_item;
+ const gchar *value = NULL;
+
+ g_variant_get(var, "as", &iter_item);
+ while (g_variant_iter_loop(iter_item, "s", &value)) {
+ if (items) {
+ char *tmp_items;
+
+ tmp_items = (char *) malloc(strlen(items) + 1 + strlen(value) + 1);
+ if (items) {
+ sprintf(tmp_items, "%s,%s", items, value);
+ free(items);
+ items = tmp_items;
+ }
+ } else {
+ items = strdup(value);
+ }
+ }
+ g_variant_iter_free(iter_item);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ g_variant_iter_free(iter);
+ g_variant_unref(message);
+ }
+
+ return items;
+}
+
+static void connman_set_items(GDBusConnection *connection, char *profile,
+ const char *keystr, char *items)
+{
+ GVariant *message = NULL;
+ GVariantBuilder *builder = NULL;
+ GVariant *params = NULL;
+ char *strings = strdup(items);
+ char *addr = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+ if ((addr = strtok(strings, ", ")) != NULL) {
+ do {
+ g_variant_builder_add(builder, "s", addr);
+ } while ((addr = strtok(NULL, ", ")) != NULL);
+ }
+ free(strings);
+ params = g_variant_new("(sv)", keystr,
+ g_variant_builder_end(builder));
+ g_variant_builder_unref(builder);
+
+ message = connman_method_call(connection, CONNMAN_SERVICE, profile,
+ CONNMAN_INTERFACE_SERVICE, "SetProperty", params);
+ if (message)
+ g_variant_unref(message);
+
+}
+
+static char *connman_get_nameservers(GDBusConnection *connection, char *profile)
+{
+ return connman_get_items(connection, profile, "Nameservers");
+}
+
+static char *connman_get_nameservers_conf(GDBusConnection *connection, char *profile)
+{
+ return connman_get_items(connection, profile, "Nameservers.Configuration");
+}
+
+static void connman_set_nameservers(GDBusConnection *connection, char *profile,
+ char *nameservers)
+{
+ return connman_set_items(connection, profile,
+ "Nameservers.Configuration", nameservers);
+}
+
+static char *connman_get_domains(GDBusConnection *connection, char *profile)
+{
+ return connman_get_items(connection, profile, "Domains");
+}
+
+static char *connman_get_domains_conf(GDBusConnection *connection, char *profile)
+{
+ return connman_get_items(connection, profile, "Domains.Configuration");
+}
+
+static void connman_set_domains(GDBusConnection *connection, char *profile,
+ char *domains)
+{
+ return connman_set_items(connection, profile,
+ "Domains.Configuration", domains);
+}
+
+static int add_dns_servers(char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt)
+{
+ char *profile = NULL;
+ char *items = NULL;
+ char *org_items = NULL;
+ char *new_items = NULL;
+ unsigned int i;
+
+ connman_connection_open();
+
+ profile = connman_default_profile(global_connection);
+ if (profile == NULL) {
+ LOGE("connman_default_profile failed");
+ connman_connection_close(global_connection);
+ return VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ LOGD("profile : %s\n", profile);
+
+ /* add name servers */
+ org_items = connman_get_nameservers(global_connection, profile);
+
+ if (org_items) {
+ LOGD("original DNS : %s\n", org_items);
+ /* nr_dns = comma(,) count */
+ items = (char *) calloc((total_dns_string_cnt + nr_dns + strlen(org_items) + 1), sizeof(char));
+ if (items == NULL) {
+ LOGE("OOM while malloc\n");
+ return VPNSVC_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(items, org_items, strlen(org_items));
+ for (i = 0 ; i < nr_dns ; i++) {
+ strcat(items, ",");
+ strcat(items, dns_servers[i]);
+ }
+ free(org_items);
+ org_items = NULL;
+ } else {
+ /* nr_dns = comma(,) count + end null char */
+ items = (char *) calloc(total_dns_string_cnt + nr_dns, sizeof(char));
+ if (items == NULL) {
+ LOGE("OOM while malloc\n");
+ return VPNSVC_ERROR_OUT_OF_MEMORY;
+ }
+ for (i = 0 ; i < nr_dns ; i++) {
+ strcat(items, dns_servers[i]);
+ if (i != nr_dns - 1)
+ strcat(items, ",");
+ }
+ }
+
+ if (items) {
+ LOGD("adding DNS : %s\n", items);
+ connman_set_nameservers(global_connection, profile, items);
+ free(items);
+ items = NULL;
+ }
+
+ /* print new DNSs */
+ new_items = connman_get_nameservers_conf(global_connection, profile);
+ LOGD("new_dns : %s\n", new_items);
+
+ if (new_items)
+ free(new_items);
+ free(profile);
+ return VPNSVC_ERROR_NONE;
+}
+
+static int del_dns_servers()
+{
+ char *profile = NULL;
+
+ connman_connection_open();
+
+ profile = connman_default_profile(global_connection);
+ if (profile == NULL) {
+ LOGE("connman_default_profile failed");
+ connman_connection_close(global_connection);
+ return VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ LOGD("profile : %s", profile);
+
+ /* del name servers */
+ connman_set_nameservers(global_connection, profile, "");
+
+ if (profile)
+ free(profile);
+
+ return VPNSVC_ERROR_NONE;
+}
+
+static int add_dns_suffix(const char* dns_suffix, size_t dns_suffix_len)
+{
+ char *profile = NULL;
+ char *items = NULL;
+ char *org_items = NULL;
+ char *new_items = NULL;
+
+ connman_connection_open();
+
+ profile = connman_default_profile(global_connection);
+ if (profile == NULL) {
+ LOGE("connman_default_profile failed");
+ connman_connection_close(global_connection);
+ return VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ LOGD("profile : %s", profile);
+
+ /* add name servers */
+ org_items = connman_get_domains(global_connection, profile);
+
+ if (org_items) {
+ LOGD("original DNS suffix : %s", org_items);
+ /* comma(,) and end null character included */
+ items = (char *) calloc((dns_suffix_len + strlen(org_items) + 2), sizeof(char));
+ if (items == NULL) {
+ LOGE("OOM while malloc");
+ return VPNSVC_ERROR_OUT_OF_MEMORY;
+ }
+ strncpy(items, org_items, strlen(org_items));
+ strcat(items, ",");
+ strcat(items, dns_suffix);
+ free(org_items);
+ org_items = NULL;
+ } else {
+ /* nr_dns = comma(,) count + end null char */
+ items = (char *) calloc((dns_suffix_len + 1), sizeof(char));
+ if (items == NULL) {
+ LOGE("OOM while malloc");
+ return VPNSVC_ERROR_OUT_OF_MEMORY;
+ }
+ strcat(items, dns_suffix);
+ }
+
+ if (items) {
+ LOGD("adding DNS suffix : %s\n", items);
+ connman_set_domains(global_connection, profile, items);
+ free(items);
+ items = NULL;
+ }
+
+ /* print new domains */
+ new_items = connman_get_domains_conf(global_connection, profile);
+ LOGD("new DNS suffix : %s\n", new_items);
+
+ if (new_items)
+ free(new_items);
+
+ if (profile)
+ free(profile);
+
+ return VPNSVC_ERROR_NONE;
+}
+
+static int del_dns_suffix()
+{
+ char *profile = NULL;
+
+ connman_connection_open();
+
+ profile = connman_default_profile(global_connection);
+ if (profile == NULL) {
+ LOGE("connman_default_profile failed");
+ connman_connection_close(global_connection);
+ return VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ LOGD("profile : %s", profile);
+
+ /* del DNS suffix */
+ connman_set_domains(global_connection, profile, "");
+
+ if (profile)
+ free(profile);
+
+ return VPNSVC_ERROR_NONE;
+}
+
+
+static void iptables_exec(char *cmdline)
+{
+ FILE *fp = NULL;
+
+ fp = popen(cmdline, "r");
+
+ if (fp != NULL)
+ pclose(fp);
+}
+
+static void iptables_register(void)
+{
+ int size = 0;
+ char buf[8192], *filter;
+
+ filter = iptables_filter_out;
+ snprintf(buf + size, sizeof(buf) - size, iptables_register_fmt,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, filter, iptables_filter_prefix, filter);
+ size = strlen(buf);
+ filter = iptables_filter_in;
+ snprintf(buf + size, sizeof(buf) - size, iptables_register_fmt,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, filter, iptables_filter_prefix, filter);
+ LOGD("iptable reg cmd : %s", buf);
+ iptables_exec(buf);
+}
+
+static void iptables_unregister(void)
+{
+ int size = 0;
+ char buf[8192], *filter;
+
+ filter = iptables_filter_out;
+ snprintf(buf + size, sizeof(buf) - size, iptables_unregister_fmt,
+ iptables_cmd, filter, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter);
+ size = strlen(buf);
+ filter = iptables_filter_in;
+ snprintf(buf + size, sizeof(buf) - size, iptables_unregister_fmt,
+ iptables_cmd, filter, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter,
+ iptables_cmd, iptables_filter_prefix, filter);
+ LOGD("iptable unreg cmd : %s", buf);
+ iptables_exec(buf);
+}
+
+static void iptables_rule(const char c, const char *addr, const int mask)
+{
+ int size = 0;
+ char buf[4096];
+
+ snprintf(buf + size, sizeof(buf) - size, iptables_rule_fmt, iptables_cmd, c,
+ iptables_filter_prefix, iptables_filter_out, 'd', addr, mask);
+ size = strlen(buf);
+ snprintf(buf + size, sizeof(buf) - size, iptables_rule_fmt, iptables_cmd, c,
+ iptables_filter_prefix, iptables_filter_in, 's', addr, mask);
+ LOGD("iptable cmd : %s", buf);
+ iptables_exec(buf);
+}
+
+static void iptables_rule_interface(const char c, const char *addr, const int mask, const char *interface)
+{
+ int size = 0;
+ char buf[4096];
+
+ snprintf(buf + size, sizeof(buf) - size,
+ iptables_rule_with_interface_fmt, iptables_cmd,
+ c, iptables_filter_prefix, iptables_filter_out,
+ 'o', interface, 'd', addr, mask);
+ size = strlen(buf);
+ snprintf(buf + size, sizeof(buf) - size,
+ iptables_rule_with_interface_fmt, iptables_cmd,
+ c, iptables_filter_prefix, iptables_filter_in,
+ 'i', interface, 's', addr, mask);
+ LOGD("iptable cmd : %s", buf);
+ iptables_exec(buf);
+}
+
+void iptables_add_orig(const char *addr, const int mask)
+{
+ iptables_rule_interface('I', addr, mask, iptables_filter_interface_wlan);
+}
+
+void iptables_delete_orig(const char *addr, const int mask)
+{
+ iptables_rule_interface('D', addr, mask, iptables_filter_interface_wlan);
+}
+
+void iptables_add(const char *addr, const int mask)
+{
+ iptables_rule('I', addr, mask);
+}
+
+void iptables_delete(const char *addr, const int mask)
+{
+ iptables_rule('D', addr, mask);
+}
+
+static int get_interface_index(const char *tun_name)
+{
+ struct ifreq ifr;
+ int sk = 0;
+
+ LOGD("enter get_interface_index, tun_name : %s", tun_name);
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ LOGE("socket failed : %s", strerror(errno));
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ if (*tun_name)
+ strncpy(ifr.ifr_name, tun_name, strlen(tun_name));
+
+ /* get an interface name by ifindex */
+ if (ioctl(sk, SIOCGIFINDEX, &ifr) < 0) {
+ LOGE("ioctl SIOCGIFINDEX failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ close(sk);
+
+ return ifr.ifr_ifindex;
+}
+
+
+int vpn_daemon_init(const char* tun_name, size_t tun_name_len, int fd, vpnsvc_tun_s *handle_s)
+{
+ struct ifreq ifr;
+ size_t len = 0;
+
+ LOGD("enter vpn_daemon_init, tun_name : %s, tun_name_len : %d, fd : %d\n", tun_name, tun_name_len, fd);
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ /* Flags: IFF_TUN - TUN device (no Ethernet headers)
+ * IFF_TAP - TAP device
+ *
+ * IFF_NO_PI - Do not provide packet information
+ */
+
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+
+ if (*tun_name)
+ strncpy(ifr.ifr_name, tun_name, tun_name_len);
+
+ LOGD("before init, ifindex : %d", ifr.ifr_ifindex);
+
+ if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
+ LOGE("TUNSETIFF Failed : %s", strerror(errno));
+ close(fd);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ if (ioctl(fd, TUNSETOWNER, 5000) < 0) {
+ LOGE("TUNSETOWNER Failed : %s", strerror(errno));
+ close(fd);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ if (ioctl(fd, TUNSETPERSIST, 1) < 0) {
+ LOGE("TUNSETPERSIST Failed : %s", strerror(errno));
+ close(fd);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ handle_s->fd = 0; /* server fd does not meaning */
+ handle_s->index = get_interface_index(tun_name);
+ len = strlen(ifr.ifr_name);
+ strncpy(handle_s->name, ifr.ifr_name, len);
+ handle_s->name[len] = '\0';
+
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_deinit(const char* dev_name)
+{
+ char buf[100];
+ FILE *fp = NULL;
+
+ snprintf(buf, sizeof(buf), "/usr/sbin/ip link del %s", dev_name);
+ LOGD("link delete cmd : %s", buf);
+
+ fp = popen(buf, "r");
+ if (fp != NULL) {
+ pclose(fp);
+ return VPNSVC_ERROR_NONE;
+ } else {
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+}
+
+int vpn_daemon_protect(int socket_fd, const char* dev_name)
+{
+ int ret = VPNSVC_ERROR_NONE;
+ LOGD("enter vpn_daemon_protect, socket : %d, dev_name : %s\n", socket_fd, dev_name);
+
+ ret = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE,
+ dev_name, strlen(dev_name));
+
+ if (ret < 0) {
+ LOGD("setsockopt failed : %d, %s", ret, strerror(errno));
+ ret = VPNSVC_ERROR_IO_ERROR;
+ } else {
+ ret = VPNSVC_ERROR_NONE;
+ }
+
+ return ret;
+}
+
+int vpn_daemon_up(int tun_index, const char* local_ip, const char* remote_ip,
+ const struct vpnsvc_route* routes, size_t nr_routes,
+ char** dns_servers, size_t nr_dns, size_t total_dns_string_cnt,
+ const char* dns_suffix, const unsigned int mtu) {
+
+ struct sockaddr_in local_addr;
+ struct sockaddr_in remote_addr;
+ struct ifreq ifr_tun;
+ int sk;
+ int ret = VPNSVC_ERROR_NONE;
+
+ LOGD("enter vpn_daemon_up");
+
+ LOGD("tun_index : %d", tun_index);
+ LOGD("local ip : %s", local_ip);
+ LOGD("remote ip : %s", remote_ip);
+ LOGD("route pointer : %p, nr_routes : %d, dns_server pointer : %p, nr_dns : %d, dns_suffix : %s, mtu : %d", routes, nr_routes, dns_servers, nr_dns, dns_suffix, mtu);
+
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ LOGE("socket failed : %s", strerror(errno));
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ memset(&ifr_tun, 0, sizeof(ifr_tun));
+ ifr_tun.ifr_ifindex = tun_index;
+
+ /* get an interface name by ifindex */
+ if (ioctl(sk, SIOCGIFNAME, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCGIFNAME failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ /* local ip setting */
+ memset(&local_addr, 0, sizeof(local_addr));
+ local_addr.sin_addr.s_addr = inet_addr(local_ip); /* network byte order */
+ local_addr.sin_family = AF_INET;
+ memcpy(&ifr_tun.ifr_addr, &local_addr, sizeof(ifr_tun.ifr_addr));
+ if (ioctl(sk, SIOCSIFADDR, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCSIFADDR failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ /* remote ip setting */
+ memset(&remote_addr, 0, sizeof(remote_addr));
+ remote_addr.sin_addr.s_addr = inet_addr(remote_ip); /*network byte order*/
+ remote_addr.sin_family = AF_INET;
+ memcpy(&ifr_tun.ifr_dstaddr, &remote_addr, sizeof(ifr_tun.ifr_dstaddr));
+ if (ioctl(sk, SIOCSIFDSTADDR, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCSIFDSTADDR failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ /* set the flags for vpn up */
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCGIFFLAGS failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ ifr_tun.ifr_flags |= IFF_UP;
+ ifr_tun.ifr_flags |= IFF_RUNNING;
+
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCSIFFLAGS failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ /* mtu setting */
+ if (ioctl(sk, SIOCGIFMTU, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCGIFMTU failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ if (mtu > 0 && ifr_tun.ifr_mtu != (int)mtu) {
+ ifr_tun.ifr_mtu = mtu;
+ if (ioctl(sk, SIOCSIFMTU, &ifr_tun) < 0) {
+ LOGE("ioctl SIOCSIFMTU failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+ }
+
+ close(sk);
+
+ /* add routes */
+ if (nr_routes > 0) {
+ ret = add_routes(ifr_tun.ifr_name, routes, nr_routes);
+ if (ret != VPNSVC_ERROR_NONE) {
+ LOGE("add_routes failed");
+ return ret;
+ }
+ }
+
+ /* add DNS servers */
+ if (nr_dns > 0) {
+ ret = add_dns_servers(dns_servers, nr_dns, total_dns_string_cnt);
+ if (ret != VPNSVC_ERROR_NONE) {
+ LOGE("add_dns failed");
+ return ret;
+ }
+ }
+
+ /* add_dns_suffix */
+ if (dns_suffix) {
+ ret = add_dns_suffix(dns_suffix, strlen(dns_suffix));
+ if (ret != VPNSVC_ERROR_NONE) {
+ LOGE("add_dns_suffix failed");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+int vpn_daemon_down(int tun_index)
+{
+ struct ifreq ifr, addr_ifr;
+ struct sockaddr_in *addr = NULL;
+ int sk;
+
+ sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (sk < 0) {
+ LOGE("socket failed : %s", strerror(errno));
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = tun_index;
+
+ if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
+ LOGE("ioctl SIOCGIFNAME failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
+ LOGE("ioctl SIOCGIFFLAGS failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ memset(&addr_ifr, 0, sizeof(addr_ifr));
+ memcpy(&addr_ifr.ifr_name, &ifr.ifr_name, sizeof(ifr.ifr_name) - 1);
+ addr = (struct sockaddr_in *)&addr_ifr.ifr_addr;
+ addr->sin_family = AF_INET;
+ if (ioctl(sk, SIOCSIFADDR, &addr_ifr) < 0)
+ LOGD("ioctl SIOCSIFADDR (could not clear IP address) failed : %s", strerror(errno));
+
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ LOGD("Interface already down");
+ close(sk);
+ return VPNSVC_ERROR_NONE;
+ }
+
+ ifr.ifr_flags = (ifr.ifr_flags & ~IFF_UP) | IFF_DYNAMIC;
+ if (ioctl(sk, SIOCSIFFLAGS, &ifr) < 0) {
+ LOGE("ioctl SIOCSIFFLAGS (interface down) failed : %s", strerror(errno));
+ close(sk);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ close(sk);
+
+ /* routes are will be removed automatically while down interfaces */
+ /* remove dns servers */
+ del_dns_servers();
+
+ /* remove dns suffix */
+ del_dns_suffix();
+
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_block_networks(const struct vpnsvc_route* nets_vpn, size_t nr_nets_vpn,
+ const struct vpnsvc_route* nets_orig, size_t nr_nets_orig) {
+ unsigned int i;
+
+ /* iptable chain regist */
+ iptables_register();
+
+ for (i = 0; i < nr_nets_vpn; i++) {
+ LOGD("block[%d] ip/mask : %s/%d", i, nets_vpn[i].dest, nets_vpn[i].prefix);
+ iptables_add(nets_vpn[i].dest, nets_vpn[i].prefix);
+ }
+
+ for (i = 0; i < nr_nets_orig; i++) {
+ LOGD("allow[%d] ip/mask : %s/%d", i, nets_orig[i].dest, nets_orig[i].prefix);
+ iptables_add_orig(nets_orig[i].dest, nets_orig[i].prefix);
+ }
+
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpn_daemon_unblock_networks(void)
+{
+ iptables_unregister();
+
+ return VPNSVC_ERROR_NONE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 <unistd.h>
+#include <stdlib.h> /* exit, EXIT_FAILURE */
+#include <dlog/dlog.h>
+
+#include "vpnsvc.h"
+#include "vpndbus.h"
+
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "VPNSVC_DAEMON"
+
+static GMainLoop *main_loop = NULL;
+
+static void __vpnsvc_got_name_cb(void)
+{
+ vpnsvc_create_and_init();
+}
+
+int main(void)
+{
+ int ret;
+
+ LOGD("VPN Service");
+ if (daemon(0, 0) != 0)
+ LOGD("Cannot start daemon");
+
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ g_type_init();
+#endif
+
+ main_loop = g_main_loop_new(NULL, FALSE);
+ if (main_loop == NULL) {
+ LOGE("Couldn't create GMainLoop\n");
+ return 0;
+ }
+
+ ret = vpnsvc_setup_gdbus(__vpnsvc_got_name_cb);
+ if (ret > 0) {
+ LOGE("_vpnsvc_setup_gdbus is failed\n");
+ return 0;
+ }
+
+ g_main_loop_run(main_loop);
+
+ vpnsvc_cleanup_gdbus();
+
+ return 0;
+}
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <dlog/dlog.h>
+
+#include "vpndbus.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+static GDBusObjectManagerServer *manager_server_vpn = NULL;
+static guint owner_id = 0;
+static vpnsvc_got_name_cb g_callback = NULL;
+
+struct gdbus_conn_data {
+ GDBusConnection *connection;
+ int conn_ref_count;
+ GCancellable *cancellable;
+};
+
+static struct gdbus_conn_data gconn_data = {NULL, 0, NULL};
+
+GDBusObjectManagerServer *vpnsvc_get_vpn_manager(void)
+{
+ return manager_server_vpn;
+}
+
+GDBusConnection *vpnsvc_gdbus_get_connection(void)
+{
+ return gconn_data.connection;
+}
+
+GCancellable *vpnsvc_gdbus_get_gdbus_cancellable(void)
+{
+ return gconn_data.cancellable;
+}
+
+void vpnsvc_gdbus_pending_call_ref(void)
+{
+ g_object_ref(gconn_data.connection);
+
+ __sync_fetch_and_add(&gconn_data.conn_ref_count, 1);
+}
+
+void vpnsvc_gdbus_pending_call_unref(void)
+{
+ if (gconn_data.conn_ref_count < 1)
+ return;
+
+ g_object_unref(gconn_data.connection);
+
+ if (__sync_sub_and_fetch(&gconn_data.conn_ref_count, 1) < 1) {
+ /* TODO: Check this
+ * gconn_data.connection = NULL;
+ */
+ }
+}
+
+int vpnsvc_create_gdbus_call(GDBusConnection *conn)
+{
+ if (gconn_data.connection != NULL) {
+ LOGE("Connection already set");
+ return -1;
+ }
+
+ gconn_data.connection = conn;
+ if (gconn_data.connection == NULL) {
+ LOGE("Failed to connect to the D-BUS daemon");
+ return -1;
+ }
+
+ gconn_data.cancellable = g_cancellable_new();
+
+ return 0;
+}
+
+
+gboolean vpnsvc_invoke_dbus_method_nonblock(const char *dest, const char *path,
+ const char *interface_name, const char *method, GVariant *params,
+ GAsyncReadyCallback notify_func)
+{
+ GDBusConnection *connection = NULL;
+
+ LOGD("[GDBUS Async] %s %s %s", interface_name, method, path);
+
+ connection = vpnsvc_gdbus_get_connection();
+ if (connection == NULL) {
+ LOGE("Failed to get gdbus connection");
+ return FALSE;
+ }
+
+ g_dbus_connection_call(connection,
+ dest,
+ path,
+ interface_name,
+ method,
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ vpnsvc_gdbus_get_gdbus_cancellable(),
+ (GAsyncReadyCallback) notify_func,
+ NULL);
+
+ if (notify_func != NULL)
+ vpnsvc_gdbus_pending_call_ref();
+
+ return TRUE;
+}
+
+GVariant *vpnsvc_invoke_dbus_method(const char *dest, const char *path,
+ const char *interface_name, const char *method, GVariant *params)
+{
+
+ GError *error = NULL;
+ GVariant *reply = NULL;
+ GDBusConnection *connection;
+
+ connection = vpnsvc_gdbus_get_connection();
+ if (connection == NULL) {
+ LOGE("Failed to get GDBusconnection");
+ return reply;
+ }
+
+ reply = g_dbus_connection_call_sync(
+ connection,
+ dest,
+ path,
+ interface_name,
+ method,
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ vpnsvc_gdbus_get_gdbus_cancellable(),
+ &error);
+
+ if (reply == NULL) {
+ if (error != NULL) {
+ LOGE("g_dbus_connection_call_sync() failed"
+ "error [%d: %s]", error->code, error->message);
+ g_error_free(error);
+ } else {
+ LOGE("g_dbus_connection_call_sync() failed");
+ }
+
+ return NULL;
+ }
+
+ return reply;
+}
+
+static void __vpnsvc_got_bus_cb(GDBusConnection *conn, const gchar *name,
+ gpointer user_data)
+{
+ LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+
+ vpnsvc_create_gdbus_call(conn);
+}
+
+static void __vpnsvc_got_name_cb(GDBusConnection *conn, const gchar *name,
+ gpointer user_data)
+{
+ LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+
+ if (g_callback != NULL)
+ g_callback();
+}
+
+static void __vpnsvc_lost_name_cb(GDBusConnection *conn, const gchar *name,
+ gpointer user_data)
+{
+ LOGD("connection: [%p] name: [%s] user_data: [%p]", conn, name, user_data);
+ /* May service name is already in use */
+ LOGE("Service name is already in use");
+
+ /* The result of DBus name request is only permitted,
+ * such as DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER.
+ */
+ exit(2);
+}
+
+int vpnsvc_setup_gdbus(vpnsvc_got_name_cb cb)
+{
+ LOGD("VPN Service Setup!");
+
+ g_callback = cb;
+
+ manager_server_vpn = g_dbus_object_manager_server_new(
+ VPNSERVICE_PATH);
+ if (manager_server_vpn == NULL) {
+ LOGE("Manager server for VPNSERVICE_PATH not created.");
+ exit(1);
+ }
+
+ owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, VPNSERVICE_SERVICE,
+ G_BUS_NAME_OWNER_FLAGS_NONE, __vpnsvc_got_bus_cb,
+ __vpnsvc_got_name_cb, __vpnsvc_lost_name_cb,
+ NULL, NULL);
+ if (!owner_id) {
+ LOGE("Could not get system bus!");
+ return -EIO;
+ }
+
+ LOGI("Got system bus!");
+ return 0;
+}
+
+void vpnsvc_cleanup_gdbus(void)
+{
+ LOGD("VPN Service Cleanup!");
+
+ g_bus_unown_name(owner_id);
+
+ return;
+}
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <dlog/dlog.h>
+#include <gio/gunixfdlist.h>
+
+#include "vpnsvc.h"
+#include "vpndbus.h"
+#include "vpn_service_daemon.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_DAEMON"
+
+static Vpnsvc *vpnsvc = NULL;
+
+/*********************
+ * Handler Functions *
+ ********************/
+gboolean handle_vpn_init(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_tun_name,
+ guint arg_tun_name_len)
+{
+ LOGD("handle_vpn_init");
+
+ vpnsvc_tun_s handle_s;
+ int result = VPNSVC_ERROR_NONE;
+ GDBusMessage *msg;
+ GUnixFDList *fd_list;
+ int fd_list_length;
+ const int *fds;
+
+ LOGD("vpn_init, %s, %u\n", arg_tun_name, arg_tun_name_len);
+
+ msg = g_dbus_method_invocation_get_message(invocation);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+ fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
+
+ if (fd_list_length <= 0)
+ LOGD("D-Bus Message doesn't contain any fd!");
+
+ LOGD("fd:%d\n", *fds);
+
+ result = vpn_daemon_init(arg_tun_name, arg_tun_name_len, *fds, &handle_s);
+
+ LOGD("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s",
+ handle_s.fd, handle_s.index, handle_s.name);
+
+ vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_deinit(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_dev_name)
+{
+ int result = VPNSVC_ERROR_NONE;
+
+ LOGD("handle_vpn_deinit");
+ LOGD("vpn_deinit, %s\n", arg_dev_name);
+
+ result = vpn_daemon_deinit(arg_dev_name);
+
+ vpnsvc_complete_vpn_deinit(object, invocation, result);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_protect(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_dev_name)
+{
+ int result = VPNSVC_ERROR_NONE;
+ int socket;
+ GDBusMessage *msg;
+ GUnixFDList *fd_list;
+ int fd_list_length;
+ const int *fds;
+
+ LOGD("handle_vpn_protect");
+
+ msg = g_dbus_method_invocation_get_message(invocation);
+ fd_list = g_dbus_message_get_unix_fd_list(msg);
+ fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
+ if (fd_list_length <= 0)
+ LOGD("D-Bus Message doesn't contain any fd!");
+
+ socket = *fds;
+ LOGD("vpn_protect, %d, %s\n", socket, arg_dev_name);
+
+ result = vpn_daemon_protect(socket, arg_dev_name);
+
+ vpnsvc_complete_vpn_protect(object, invocation, result);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_up(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ gint arg_tun_index,
+ const gchar *arg_local_ip,
+ const gchar *arg_remote_ip,
+ GVariant *arg_routes,
+ guint arg_nr_routes,
+ GVariant *arg_dns_servers,
+ guint arg_nr_dns,
+ const gchar *arg_dns_suffix,
+ guint arg_mtu)
+{
+ int result = VPNSVC_ERROR_NONE;
+
+ LOGD("handle_vpn_up");
+
+ struct vpnsvc_route* routes = NULL;
+ char **dns_servers = NULL;
+
+ unsigned int i = 0;
+ size_t total_dns_string_cnt = 0;
+ gchar* temp_dns_server;
+ GVariantIter iter;
+
+ gchar* route_dest;
+ gint route_prefix;
+
+ LOGD("tun_index : %d", arg_tun_index);
+ LOGD("local ip : %s", arg_local_ip);
+ LOGD("remote ip : %s", arg_remote_ip);
+ LOGD("dns_suffix : %s", arg_dns_suffix);
+ LOGD("mtu : %u", arg_mtu);
+ LOGD("arg_routes: %p", arg_routes);
+ LOGD("nr_routes : %u", arg_nr_routes);
+ LOGD("arg_dns_servers: %p", arg_dns_servers);
+ LOGD("nr_dns : %u", arg_nr_dns);
+
+ /* arg_routes check */
+ if (arg_nr_routes > 0) {
+ if (arg_routes != NULL) {
+ GVariant *dict = g_variant_get_variant(arg_routes);
+ routes = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_routes);
+ if (routes == NULL) {
+ LOGE("malloc failed.");
+ result = VPNSVC_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ g_variant_iter_init(&iter, dict);
+ i = 0;
+ while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+ int temp_dest_str_len = strlen(route_dest);
+ strncpy(routes[i].dest, route_dest, temp_dest_str_len);
+ routes[i].dest[temp_dest_str_len] = '\0';
+ routes[i].prefix = route_prefix;
+ LOGD("routes[%d] : %s/%d", i, (routes[i].dest == NULL) ? "" : routes[i].dest, routes[i].prefix);
+ i++;
+ }
+ }
+ }
+
+
+ /* arg_nr_dns check */
+ if (arg_nr_dns > 0) {
+ if (arg_dns_servers != NULL) {
+ GVariant *array = g_variant_get_variant(arg_dns_servers);
+ dns_servers = (char **)malloc(arg_nr_dns*sizeof(char *));
+ if (dns_servers == NULL) {
+ LOGE("malloc failed.");
+ result = VPNSVC_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ g_variant_iter_init(&iter, array);
+ i = 0;
+ while (g_variant_iter_loop(&iter, "s", &temp_dns_server)) {
+ int temp_dns_str_len = strlen(temp_dns_server);
+ dns_servers[i] = (char *)malloc((temp_dns_str_len+1)*sizeof(char));
+ strncpy(dns_servers[i], temp_dns_server, strlen(temp_dns_server));
+ dns_servers[i][temp_dns_str_len] = '\0';
+ total_dns_string_cnt += temp_dns_str_len;
+ LOGD("dns_servers[%d] : %s", i, (dns_servers[i] == NULL) ? "" : dns_servers[i]);
+ i++;
+ }
+ }
+ }
+
+ result = vpn_daemon_up(arg_tun_index, arg_local_ip, arg_remote_ip,
+ routes, arg_nr_routes, dns_servers, arg_nr_dns,
+ total_dns_string_cnt, arg_dns_suffix, arg_mtu);
+done:
+ /* free pointers */
+ if (routes)
+ free(routes);
+
+ if (dns_servers) {
+ for (i = 0; i < arg_nr_dns; i++) {
+ if (dns_servers[i])
+ free(dns_servers[i]);
+ }
+ free(dns_servers);
+ }
+
+ vpnsvc_complete_vpn_up(object, invocation, result);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_down(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ gint arg_tun_index)
+{
+ LOGD("handle_vpn_down");
+ int result = VPNSVC_ERROR_NONE;
+
+ LOGD("vpn_down, %d\n", arg_tun_index);
+
+ result = vpn_daemon_down(arg_tun_index);
+
+ vpnsvc_complete_vpn_down(object, invocation, result);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_block_networks(Vpnsvc *object,
+ GDBusMethodInvocation *invocation,
+ GVariant *arg_nets_vpn,
+ guint arg_nr_nets_vpn,
+ GVariant *arg_nets_orig,
+ guint arg_nr_nets_orig)
+{
+ LOGD("handle_vpn_block_networks");
+ int result = VPNSVC_ERROR_NONE;
+
+ struct vpnsvc_route* nets_vpn = NULL;
+ struct vpnsvc_route* nets_orig = NULL;
+
+ int i = 0;
+ GVariantIter iter;
+ gchar* route_dest;
+ gint route_prefix;
+
+ LOGD("vpn_block_networks");
+
+ /* arg_nets_vpn check */
+ if (arg_nr_nets_vpn > 0) {
+ if (arg_nets_vpn != NULL) {
+ GVariant *dict_nets_vpn = g_variant_get_variant(arg_nets_vpn);
+ nets_vpn = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_nets_vpn);
+ if (nets_vpn == NULL) {
+ LOGE("malloc failed.");
+ result = VPNSVC_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ g_variant_iter_init(&iter, dict_nets_vpn);
+ i = 0;
+ while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+ int tmp_route_len = strlen(route_dest);
+ strncpy(nets_vpn[i].dest, route_dest, tmp_route_len);
+ nets_vpn[i].dest[tmp_route_len] = '\0';
+ nets_vpn[i].prefix = route_prefix;
+ LOGD("nets_vpn[%d] : %s/%d", i, (nets_vpn[i].dest == NULL) ? "" : nets_vpn[i].dest, nets_vpn[i].prefix);
+ i++;
+ }
+ }
+ }
+
+ /* arg_nets_orig check */
+ if (arg_nr_nets_orig > 0) {
+ if (arg_nets_orig != NULL) {
+ GVariant *dict_nets_orig = g_variant_get_variant(arg_nets_orig);
+ nets_orig = (struct vpnsvc_route*)malloc(sizeof(struct vpnsvc_route)*arg_nr_nets_orig);
+ if (nets_orig == NULL) {
+ LOGE("malloc failed.");
+ result = VPNSVC_ERROR_OUT_OF_MEMORY;
+ goto done;
+ }
+ g_variant_iter_init(&iter, dict_nets_orig);
+ i = 0;
+ while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
+ int tmp_route_len = strlen(route_dest);
+ strncpy(nets_orig[i].dest, route_dest, tmp_route_len);
+ nets_orig[i].dest[tmp_route_len] = '\0';
+ nets_orig[i].prefix = route_prefix;
+ LOGD("nets_orig[%d] : %s/%d", i, (nets_orig[i].dest == NULL) ? "" : nets_orig[i].dest, nets_orig[i].prefix);
+ i++;
+ }
+ }
+ }
+
+ /* call function */
+ result = vpn_daemon_block_networks(nets_vpn, arg_nr_nets_vpn, nets_orig, arg_nr_nets_orig);
+
+done:
+ if (nets_vpn)
+ free(nets_vpn);
+
+ if (nets_orig)
+ free(nets_orig);
+
+ vpnsvc_complete_vpn_block_networks(object, invocation, result);
+
+ return TRUE;
+}
+
+gboolean handle_vpn_unblock_networks(Vpnsvc *object,
+ GDBusMethodInvocation *invocation)
+{
+ int result = VPNSVC_ERROR_NONE;
+
+ LOGD("handle_vpn_unblock_networks");
+ LOGD("vpn_unblock_networks");
+
+ result = vpn_daemon_unblock_networks();
+
+ vpnsvc_complete_vpn_unblock_networks(object, invocation, result);
+
+ return TRUE;
+}
+
+/*****************************
+ * Initializations Functions *
+ ****************************/
+Vpnsvc *get_vpnsvc_object(void)
+{
+ return vpnsvc;
+}
+
+void vpnsvc_create_and_init(void)
+{
+ LOGD("Create vpn object.");
+ GDBusInterfaceSkeleton *interface = NULL;
+ GDBusConnection *connection;
+ GDBusObjectManagerServer *server = vpnsvc_get_vpn_manager();
+ if (server == NULL)
+ return;
+
+ connection = vpnsvc_gdbus_get_connection();
+ g_dbus_object_manager_server_set_connection(server, connection);
+
+ /* Interface */
+ vpnsvc = vpnsvc_skeleton_new();
+ interface = G_DBUS_INTERFACE_SKELETON(vpnsvc);
+
+ /* VPN Service */
+ g_signal_connect(vpnsvc, "handle-vpn-init",
+ G_CALLBACK(handle_vpn_init), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-deinit",
+ G_CALLBACK(handle_vpn_deinit), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-protect",
+ G_CALLBACK(handle_vpn_protect), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-up",
+ G_CALLBACK(handle_vpn_up), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-down",
+ G_CALLBACK(handle_vpn_down), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-block-networks",
+ G_CALLBACK(handle_vpn_block_networks), NULL);
+ g_signal_connect(vpnsvc, "handle-vpn-unblock-networks",
+ G_CALLBACK(handle_vpn_unblock_networks), NULL);
+
+ if (!g_dbus_interface_skeleton_export(interface, connection,
+ VPNSERVICE_PATH, NULL)) {
+ LOGE("Export VPNSERVICE_PATH for vpn failed");
+ }
+
+ return;
+}
+
--- /dev/null
+<manifest>
+ <define>
+ <domain name="vpnsvc"/>
+ <provide>
+ <label name="vpnsvc::tun"/>
+ <label name="vpnsvc::protect"/>
+ <label name="vpnsvc::interface"/>
+ <label name="vpnsvc::block_networks"/>
+ </provide>
+ <request>
+ <smack request="connman" type="rw"/>
+ <smack request="vpnsvc::tun" type="rw"/>
+ <smack request="vpnsvc::protect" type="rw"/>
+ <smack request="vpnsvc::interface" type="rw"/>
+ <smack request="vpnsvc::block_networks" type="rw"/>
+ <smack request="device::app_logging" type="rw"/>
+ <smack request="device::sys_logging" type="rw"/>
+ <smack request="pkgmgr::db" type="rlx"/>
+ <smack request="pkgmgr::info" type="r"/>
+ <smack request="tizen::vconf::platform::r" type="rw"/>
+ <smack request="sdbd" type="rwx"/>
+ <smack request="crash-worker" type="rwx"/>
+ <smack request="vpnsvc_test" type="rwx"/>
+ <smack request="core-vpn-tests" type="rwx"/>
+ <smack request="sys-assert::core" type="rwx"/>
+ </request>
+ <permit>
+ <smack permit="dbus" type="rwx"/>
+ </permit>
+ </define>
+ <assign>
+ <filesystem path="/usr/lib/systemd/system/vpn-service-daemon.service" label="_"/>
+ <filesystem path="/usr/share/dbus-1/services/org.tizen.vpnsvc.service" label="_"/>
+ <dbus name="org.tizen.vpnsvc" own="vpnsvc" bus="system">
+ <node name="/org/tizen/vpnsvc">
+ <interface name="org.tizen.vpnsvc">
+ <annotation name="org.tizen.smack" value="vpnsvc"/>
+ <method name="vpn_init">
+ <annotation name="org.tizen.smack" value="vpnsvc::tun"/>
+ </method>
+ <method name="vpn_deinit">
+ <annotation name="org.tizen.smack" value="vpnsvc::tun"/>
+ </method>
+ <method name="vpn_protect">
+ <annotation name="org.tizen.smack" value="vpnsvc::protect"/>
+ </method>
+ <method name="vpn_up">
+ <annotation name="org.tizen.smack" value="vpnsvc::interface"/>
+ </method>
+ <method name="vpn_down">
+ <annotation name="org.tizen.smack" value="vpnsvc::interface"/>
+ </method>
+ <method name="vpn_block_networks">
+ <annotation name="org.tizen.smack" value="vpnsvc::block_networks"/>
+ </method>
+ <method name="vpn_unblock_networks">
+ <annotation name="org.tizen.smack" value="vpnsvc::block_networks"/>
+ </method>
+ </interface>
+ </node>
+ </dbus>
+ </assign>
+ <request>
+ <domain name="vpnsvc"/>
+ </request>
+</manifest>
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+
+
+#ifndef __TIZEN_NETWORK_VPN_DOC_H__
+#define __TIZEN_NETWORK_VPN_DOC_H__
+
+/**
+ * @defgroup CAPI_NETWORK_VPN_MODULE VPN
+ * @brief The VPN API provides functions for managing VPN.
+ * @ingroup CAPI_NETWORK_FRAMEWORK
+ *
+ * @section CAPI_NETWORK_VPN_MODULE_HEADER Required Header
+ * \#include <vpn_service_product.h>
+ *
+ * @section CAPI_NETWORK_VPN_MODULE_OVERVIEW Overview
+ * VPN allows your application to manage VPN features.
+ * The VPN Service enables your application to init and deinit a VPN device(tun interface),
+ * Routing management, DNS management and Firewall management.
+ */
+
+/**
+ * @defgroup CAPI_NETWORK_VPN_SERVICE_MODULE VPN Service
+ * @brief The VPN API provides functions for managing VPN.
+ * @ingroup CAPI_NETWORK_VPN_MODULE
+ *
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_HEADER Required Header
+ * \#include <vpn_service_product.h>
+ *
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_OVERVEW Overview
+ * The VPN Service functions for managing VPN.
+ * Using the VPN Service, you can implement features that allow the users of your application to:
+ * - Initialize / Deinitialize the VPN device
+ * - Routing management
+ * - DNS management
+ * - Firewall management
+ * @section CAPI_NETWORK_VPN_SERVICE_MODULE_FEATURE Related Features
+ * This API is related with the following features:\n
+ * - http://developer.samsung.com/tizen/feature/network.vpn\n
+ *
+ * It is recommended to design feature related codes in your application for reliability.\n
+ * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n
+ * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
+ * More details on featuring your application can be found from <a href="../org.tizen.mobile.native.appprogramming/html/ide_sdk_tools/feature_element.htm"><b>Feature Element</b>.</a>
+ *
+ */
+
+#endif /* __TIZEN_NETWORK_VPN_DOC_H__ */
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME capi-vpnsvc)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION 0.1)
+
+SET(requires "dlog dbus-1 glib-2.0 gio-2.0 gio-unix-2.0 capi-base-common capi-appfw-application capi-appfw-app-manager capi-system-info")
+SET(pc_requires "capi-base-common")
+
+SET(SRCS
+ src/capi_vpn_service.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/framework/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"")
+ADD_DEFINITIONS("-DFACTORYFS=\"$ENV{FACTORYFS}\"")
+ADD_DEFINITIONS("-DDATAFS=\"$ENV{DATADIR}\"")
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+ADD_LIBRARY(${PACKAGE_NAME} SHARED ${SRCS})
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} -lrt -ldl)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION lib)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/vpn_service.h DESTINATION include)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/tizen_vpn_error.h DESTINATION include)
+
+SET_TARGET_PROPERTIES(${PACKAGE_NAME}
+ PROPERTIES
+ VERSION ${FULLVER}
+ SOVERSION ${MAJORVER}
+ CLEAN_DIRECT_OUTPUT 1
+)
+
+
+SET(PC_NAME ${PACKAGE_NAME})
+SET(PC_REQUIRED ${pc_requires})
+SET(PC_CFLAGS -I\${includedir})
+SET(PC_LDFLAGS -l${PACKAGE_NAME})
+
+CONFIGURE_FILE(
+ ${PACKAGE_NAME}.pc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc
+ @ONLY
+)
+
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PACKAGE_NAME}.pc DESTINATION lib/pkgconfig)
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=/usr/lib
+includedir=/usr/include
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __VPN_SERVICE_H__
+#define __VPN_SERVICE_H__
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <fcntl.h>
+#include <dlog/dlog.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "vpn_service.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define DBUS_DAEMON_SERVICE_NAME "org.freedesktop.DBus"
+#define DBUS_DAEMON_OBJECT_NAME "/org/freedesktop/DBus"
+#define DBUS_DAEMON_INTERFACE_NAME "org.freedesktop.DBus"
+#define DBUS_DAEMON_START_SERVICE_METHOD_NAME "StartServiceByName"
+
+#define VPNSVC_DBUS_SERVICE_NAME "org.tizen.vpnsvc"
+#define VPNSVC_DBUS_INTERFACE_NAME "org.tizen.vpnsvc"
+#define VPNSVC_DBUS_INTERFACE_OBJ_NAME "/org/tizen/vpnsvc"
+
+#define _MAX_FILE_PATH_LEN 512
+#define _USER_SETTING_DEFAULT_MTU 1500
+#define _USER_SETTING_DEFAULT_SESSION "VPN_Session"
+
+#define VPN_SERVICE_FEATURE "http://tizen.org/feature/network.vpn"
+
+#define CHECK_FEATURE_SUPPORTED(feature_name) \
+ do { \
+ int feature_rv = _vpnsvc_check_feature_supported(feature_name); \
+ if (feature_rv != VPNSVC_ERROR_NONE) \
+ return feature_rv; \
+ } while(0)
+
+/**
+ * @brief This data structure has a fido data and its length.
+ */
+typedef struct _vpnsvc_tun_s {
+ GDBusConnection *connection; /**< D-Bus Connection */
+ int fd; /**< tun socket fd */
+ int index; /**< tun index (if.if_index) */
+ char name[VPNSVC_TUN_IF_NAME_LEN]; /**< tun name (if.if_name) */
+ char session[VPNSVC_SESSION_STRING_LEN];/**< session name (user setting) */
+ unsigned int mtu; /**< mtu (user setting) */
+} vpnsvc_tun_s;
+
+int _vpnsvc_check_feature_supported(const char *feature_name);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 "capi_vpn_service_private.h"
+#include <app.h>
+#include <app_info.h>
+#include <system_info.h>
+#include <gio/gunixfdlist.h>
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+GVariant *op = NULL;
+
+static __thread bool is_feature_checked = false;
+static __thread bool feature_supported = false;
+
+int _vpnsvc_check_feature_supported(const char *feature_name)
+{
+ if (is_feature_checked) {
+ if (!feature_supported) {
+ LOGE("%s feature is disabled", feature_name);
+ return VPNSVC_ERROR_NOT_SUPPORTED;
+ }
+ } else {
+ if (!system_info_get_platform_bool(feature_name, &feature_supported)) {
+ is_feature_checked = true;
+ if (!feature_supported) {
+ LOGE("%s feature is disabled", feature_name);
+ return VPNSVC_ERROR_NOT_SUPPORTED;
+ }
+ } else {
+ LOGE("Error - Feature getting from System Info");
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+ }
+
+ return VPNSVC_ERROR_NONE;
+}
+
+static void _vpnsvc_init_vpnsvc_tun_s(vpnsvc_tun_s **s)
+{
+ LOGD(" tun_s: %p", s);
+
+ if (s == NULL) return;
+ if (*s != NULL) {
+ LOGE("Can't Initialize vpnsvc_tun_s: %p", *s);
+ return;
+ }
+ *s = (vpnsvc_tun_s*)g_malloc0(sizeof(vpnsvc_tun_s));
+
+ if ((*s)->connection == NULL) {
+ GDBusConnection *connection = NULL;
+ GError* error = NULL;
+
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ g_type_init();
+#endif
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (error != NULL) {
+ LOGE("Error creating Connection: %s", error->message);
+ g_error_free(error);
+ } else {
+ LOGD("Created Connection: %p", connection);
+ (*s)->connection = connection;
+ }
+ }
+
+ /* Setting Default User Settings */
+ (*s)->mtu = _USER_SETTING_DEFAULT_MTU;
+ strncpy((*s)->session, _USER_SETTING_DEFAULT_SESSION, VPNSVC_SESSION_STRING_LEN);
+ (*s)->session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+}
+
+static void _vpnsvc_deinit_vpnsvc_tun_s(vpnsvc_tun_s *s)
+{
+ if (s == NULL) return;
+
+ if (s->connection)
+ s->connection = NULL;
+
+ s->fd = 0;
+ s->index = 0;
+ memset(s->name, 0, VPNSVC_TUN_IF_NAME_LEN);
+ memset(s->session, 0, VPNSVC_SESSION_STRING_LEN);
+
+ if (s)
+ g_free(s);
+}
+
+/*****************************************************************************
+* Global Functions Definition
+*****************************************************************************/
+GVariant *_vpnsvc_invoke_dbus_method(GDBusConnection *connection,
+ const char *dest, const char *path,
+ const char *interface_name, const char *method,
+ GVariant *params, int *dbus_error)
+{
+ GError *error = NULL;
+ GVariant *reply = NULL;
+ *dbus_error = VPNSVC_ERROR_NONE;
+
+ LOGD("Method Call() dest=%s path=%s iface=%s method=%s", dest, path, interface_name, method);
+
+ if (connection == NULL) {
+ LOGD("GDBusconnection is NULL");
+ *dbus_error = VPNSVC_ERROR_IO_ERROR;
+ return reply;
+ }
+
+ reply = g_dbus_connection_call_sync(connection,
+ dest,
+ path,
+ interface_name,
+ method,
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ NULL,
+ &error);
+
+ if (reply == NULL) {
+ if (error != NULL) {
+ LOGE("g_dbus_connection_call_sync() failed"
+ "error [%d: %s]", error->code, error->message);
+ *dbus_error = VPNSVC_ERROR_IO_ERROR;
+ g_error_free(error);
+ } else {
+ LOGE("g_dbus_connection_call_sync() failed");
+ *dbus_error = VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ return NULL;
+ }
+
+ return reply;
+}
+GVariant *_vpnsvc_invoke_dbus_method_with_fd(GDBusConnection *connection,
+ const char *dest, const char *path,
+ const char *interface_name, const char *method,
+ GVariant *params, int fd, int *dbus_error)
+{
+ GError *error = NULL;
+ GVariant *reply = NULL;
+ GUnixFDList *fd_list = NULL;
+ *dbus_error = VPNSVC_ERROR_NONE;
+
+ LOGD("Method Call() dest=%s path=%s iface=%s method=%s fd=%d", dest, path, interface_name, method, fd);
+
+ if (connection == NULL) {
+ LOGD("GDBusconnection is NULL");
+ *dbus_error = VPNSVC_ERROR_IO_ERROR;
+ return reply;
+ }
+
+ /* Setting the fd_list */
+ fd_list = g_unix_fd_list_new();
+ if (fd_list == NULL) {
+ LOGE("g_unix_fd_list_new() failed!");
+ return NULL;
+ }
+ g_unix_fd_list_append(fd_list, fd, &error);
+ if (error != NULL) {
+ LOGE("g_unix_fd_list_append() failed"
+ "error [%d: %s]", error->code, error->message);
+ *dbus_error = VPNSVC_ERROR_IO_ERROR;
+ g_error_free(error);
+ return NULL;
+ }
+
+ reply = g_dbus_connection_call_with_unix_fd_list_sync(connection,
+ dest,
+ path,
+ interface_name,
+ method,
+ params,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_REPLY_TIMEOUT,
+ fd_list,
+ NULL,
+ NULL,
+ &error);
+
+ if (reply == NULL) {
+ if (error != NULL) {
+ LOGE("g_dbus_connection_call_sync() failed"
+ "error [%d: %s]", error->code, error->message);
+ *dbus_error = VPNSVC_ERROR_IO_ERROR;
+ g_error_free(error);
+ } else {
+ LOGE("g_dbus_connection_call_sync() failed");
+ *dbus_error = VPNSVC_ERROR_IPC_FAILED;
+ }
+
+ return NULL;
+ }
+
+ return reply;
+}
+
+int vpnsvc_init(const char* tun_name, vpnsvc_tun_h *handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ int tun_fd = 0;
+
+ LOGD("enter vpnsvc_init, tun_name : %s", tun_name);
+ LOGD("handle : %p\n", handle);
+
+ /* parameter check */
+ if (tun_name == NULL || strlen(tun_name) <= 0) {
+ LOGE("tun_name is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (*handle != NULL) {
+ LOGE("handle already created");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ vpnsvc_tun_s *tmp_s = NULL;
+ _vpnsvc_init_vpnsvc_tun_s(&tmp_s);
+
+ op = _vpnsvc_invoke_dbus_method(tmp_s->connection,
+ DBUS_DAEMON_SERVICE_NAME,
+ DBUS_DAEMON_OBJECT_NAME,
+ DBUS_DAEMON_INTERFACE_NAME,
+ DBUS_DAEMON_START_SERVICE_METHOD_NAME,
+ g_variant_new("(su)", VPNSVC_DBUS_SERVICE_NAME, 0),
+ &dbus_result);
+
+ if (op == NULL) {
+ _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+ LOGD("Service [%s] Start Failed!", VPNSVC_DBUS_SERVICE_NAME);
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ unsigned int status = 0;
+ g_variant_get(op, "(u)", &status);
+ if (1 == status) { /* DBUS_START_REPLY_SUCCESS */
+ LOGD("Service [%s] Started Successfully!", VPNSVC_DBUS_SERVICE_NAME);
+ } else if (2 == status) { /* DBUS_START_REPLY_ALREADY_RUNNING */
+ LOGD("Service [%s] Already Running!", VPNSVC_DBUS_SERVICE_NAME);
+ } else {
+ LOGD("Service [%s] Not Started! Status[%d]", VPNSVC_DBUS_SERVICE_NAME, status);
+ g_variant_unref(op);
+ op = NULL;
+ _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+ g_variant_unref(op);
+ op = NULL;
+ }
+
+ if ((tun_fd = open("/dev/net/tun", O_RDWR)) < 0) {
+ LOGE("tun device open fail\n");
+ _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+
+ LOGD("client tun_fd : %d", tun_fd);
+
+ op = _vpnsvc_invoke_dbus_method_with_fd(tmp_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_init",
+ g_variant_new("(su)", tun_name, strlen(tun_name)),
+ tun_fd,
+ &dbus_result);
+
+ if (op == NULL) {
+ close(tun_fd);
+ _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ int tmp_index;
+ char* tmp_name;
+
+ g_variant_get(op, "(iis)", &result, &tmp_index, &tmp_name);
+ if (result != VPNSVC_ERROR_NONE) {
+ LOGE("vpnsvc_init() failed");
+ _vpnsvc_deinit_vpnsvc_tun_s(tmp_s);
+ result = VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ LOGD("vpnsvc_init() succeed");
+ tmp_s->fd = tun_fd; /* client fd must be set */
+ tmp_s->index = tmp_index;
+ strncpy(tmp_s->name, tmp_name, VPNSVC_TUN_IF_NAME_LEN);
+ tmp_s->name[VPNSVC_TUN_IF_NAME_LEN-1] = '\0';
+ *handle = tmp_s;
+ LOGD("handle : %p, handle->fd : %d, handle->index : %d, handle->name : %s",
+ (*handle), ((vpnsvc_tun_s*)*handle)->fd, ((vpnsvc_tun_s*)*handle)->index, ((vpnsvc_tun_s*)*handle)->name);
+ }
+ if (op) {
+ g_variant_unref(op);
+ op = NULL;
+ }
+ }
+
+ return result;
+}
+
+int vpnsvc_deinit(vpnsvc_tun_h handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_deinit, tun_fd : %d", tun_s->fd);
+
+ if (tun_s->fd > 0) {
+ op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_deinit",
+ g_variant_new("(s)", tun_s->name),
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_deinit() failed");
+ else
+ LOGD("vpn_deinit() succeed");
+ }
+
+ if (close(tun_s->fd) != 0) {
+ LOGE("tun fd close : %s", strerror(errno));
+ return VPNSVC_ERROR_IO_ERROR;
+ } else
+ LOGD("tun fd close success");
+
+ /* free allocared handle memory */
+ _vpnsvc_deinit_vpnsvc_tun_s(tun_s);
+ }
+
+ return result;
+}
+
+int vpnsvc_protect(vpnsvc_tun_h handle, int socket_fd, const char* dev_name)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_protect, socket : %d, dev_name : %s", socket_fd, dev_name);
+
+ if (tun_s->connection == NULL) {
+ LOGE("Connection Object is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* call vpnsvc_protect */
+ op = _vpnsvc_invoke_dbus_method_with_fd(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_protect",
+ g_variant_new("(s)", dev_name),
+ socket_fd,
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_protect() failed");
+ else
+ LOGD("vpn_protect() succeed");
+ }
+
+ return result;
+}
+
+int vpnsvc_up(vpnsvc_tun_h handle, const char* local_ip, const char* remote_ip,
+ const struct vpnsvc_route* routes, size_t nr_routes,
+ const char** dns_servers, size_t nr_dns_servers,
+ const char* dns_suffix)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ GVariantBuilder route_builder, dns_builder;
+ size_t i = 0;
+ GVariant *route_param = NULL;
+ GVariant *dns_param = NULL;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_up");
+
+ if (tun_s->index <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (tun_s->connection == NULL) {
+ LOGE("Connection Object is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (local_ip == NULL || remote_ip == NULL) {
+ LOGE("local and remote ip are invalid");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ LOGD("tun_index %d", tun_s->index);
+ LOGD("local_ip : %s, remote_ip : %s", local_ip, remote_ip);
+
+ /* make a route parameter */
+ g_variant_builder_init(&route_builder, G_VARIANT_TYPE("a{si}"));
+ for (i = 0 ; i < nr_routes ; i++) {
+ if (strlen(routes[i].dest) <= 0) {
+ LOGE("invalid routes[%d].dest", i);
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ g_variant_builder_add(&route_builder, "{si}", routes[i].dest, routes[i].prefix);
+ LOGD("routes[%d].dest : %s", i, routes[i].dest);
+ LOGD("routes[%d].prefix : %d", i, routes[i].prefix);
+ }
+ route_param = g_variant_builder_end(&route_builder);
+
+ /* make a dns parameter */
+ g_variant_builder_init(&dns_builder, G_VARIANT_TYPE("as"));
+ for (i = 0 ; i < nr_dns_servers ; i++) {
+ if (strlen(dns_servers[i]) <= 0) {
+ LOGE("invalid dns_servers[%d]", i);
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ LOGD("dns_servers[%d] : %s", i, dns_servers[i]);
+ g_variant_builder_add(&dns_builder, "s", dns_servers[i]);
+ }
+ dns_param = g_variant_builder_end(&dns_builder);
+
+ LOGD("dns_suffix : %s", dns_suffix);
+
+ op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_up",
+ g_variant_new("(issvuvusu)", tun_s->index, local_ip, \
+ remote_ip, route_param, nr_routes, dns_param, nr_dns_servers, \
+ dns_suffix, tun_s->mtu),
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_up() failed");
+ else
+ LOGD("vpn_up() succeed");
+ }
+
+ return result;
+}
+
+int vpnsvc_down(vpnsvc_tun_h handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_down");
+
+ if (tun_s == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (tun_s->index <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (tun_s->connection == NULL) {
+ LOGE("Connection Object is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_down",
+ g_variant_new("(i)", tun_s->index),
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_down() failed");
+ else
+ LOGD("vpn_down() succeed");
+ }
+
+ return result;
+
+}
+
+/* this API must not be use IPC */
+int vpnsvc_read(vpnsvc_tun_h handle, int timeout_ms)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ fd_set read_set;
+ struct timeval tv;
+ int ret, retVal;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (tun_s->fd <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ /* listen for events */
+ FD_ZERO(&read_set);
+ FD_SET(tun_s->fd, &read_set);
+ tv.tv_usec = timeout_ms*1000;
+ retVal = select(tun_s->fd +1, &read_set, NULL, NULL, &tv);
+
+ if (retVal) {
+ LOGD("Data is available now.\n");
+ ret = VPNSVC_ERROR_NONE;
+ } else if (retVal == 0) {
+ LOGD("No data within %d ms\n", timeout_ms);
+ ret = VPNSVC_ERROR_TIMEOUT;
+ } else {
+ LOGE("select failed\n");
+ ret = VPNSVC_ERROR_IO_ERROR;
+ }
+
+ return ret;
+}
+
+/* this API must not be use IPC */
+int vpnsvc_write(vpnsvc_tun_h handle, const char* data, size_t size)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (tun_s->fd <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ return write(tun_s->fd, data, size);
+}
+
+API int vpnsvc_block_networks(vpnsvc_tun_h handle,
+ const struct vpnsvc_route* allow_routes_vpn,
+ size_t nr_allow_routes_vpn,
+ const struct vpnsvc_route* allow_routes_orig,
+ size_t nr_allow_routes_orig)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ GVariantBuilder nets_builder;
+ size_t i = 0;
+ GVariant *nets_param_vpn;
+ GVariant *nets_param_orig;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_block_networks");
+
+ if (tun_s->connection == NULL) {
+ LOGE("Connection Object is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ /* make a route parameter for allowed VPN interface routes */
+ g_variant_builder_init(&nets_builder, G_VARIANT_TYPE("a{si}"));
+ for (i = 0 ; i < nr_allow_routes_vpn ; i++) {
+ g_variant_builder_add(&nets_builder, "{si}", allow_routes_vpn[i].dest, allow_routes_vpn[i].prefix);
+ LOGD("routes[%d].dest : %s", i, allow_routes_vpn[i].dest);
+ LOGD("routes[%d].prefix : %d", i, allow_routes_vpn[i].prefix);
+ }
+ nets_param_vpn = g_variant_builder_end(&nets_builder);
+
+ /* make a route parameter for allowed Original interface Routes */
+ g_variant_builder_init(&nets_builder, G_VARIANT_TYPE("a{si}"));
+ for (i = 0 ; i < nr_allow_routes_orig ; i++) {
+ g_variant_builder_add(&nets_builder, "{si}", allow_routes_orig[i].dest, allow_routes_orig[i].prefix);
+ LOGD("routes[%d].dest : %s", i, allow_routes_orig[i].dest);
+ LOGD("routes[%d].prefix : %d", i, allow_routes_orig[i].prefix);
+ }
+ nets_param_orig = g_variant_builder_end(&nets_builder);
+
+ op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_block_networks",
+ g_variant_new("(vuvu)", nets_param_vpn, nr_allow_routes_vpn,
+ nets_param_orig, nr_allow_routes_orig),
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_block_networks() failed");
+ else
+ LOGD("vpn_block_networks() succeed");
+ }
+
+ return result;
+}
+
+int vpnsvc_unblock_networks(vpnsvc_tun_h handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ int result = VPNSVC_ERROR_NONE;
+ int dbus_result;
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ LOGD("enter vpnsvc_unblock_networks");
+
+ if (tun_s == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ } else if (tun_s->connection == NULL) {
+ LOGE("Connection Object is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ op = _vpnsvc_invoke_dbus_method(tun_s->connection,
+ VPNSVC_DBUS_SERVICE_NAME,
+ VPNSVC_DBUS_INTERFACE_OBJ_NAME,
+ VPNSVC_DBUS_INTERFACE_NAME,
+ "vpn_unblock_networks",
+ g_variant_new("()"),
+ &dbus_result);
+
+ if (op == NULL) {
+ return VPNSVC_ERROR_IPC_FAILED;
+ } else {
+ g_variant_get(op, "(i)", &result);
+ if (result != VPNSVC_ERROR_NONE)
+ LOGE("vpn_unblock_networks() failed");
+ else
+ LOGD("vpn_unblock_networks() succeed");
+ }
+
+ return result;
+}
+
+int vpnsvc_get_tun_fd(vpnsvc_tun_h handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (tun_s->fd <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ return tun_s->fd;
+}
+
+int vpnsvc_get_tun_index(vpnsvc_tun_h handle)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (tun_s->index <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ return tun_s->index;
+}
+
+int vpnsvc_get_tun_name(vpnsvc_tun_h handle, char* tun_name)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (strlen(tun_s->name) <= 0) {
+ LOGE("invalid handle");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ strncpy(tun_name, tun_s->name, VPNSVC_TUN_IF_NAME_LEN);
+ tun_name[VPNSVC_TUN_IF_NAME_LEN-1] = '\0';
+
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_mtu(vpnsvc_tun_h handle, int mtu)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (mtu <= 0) {
+ LOGE("Incorrect MTU Size = %d", mtu);
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ tun_s->mtu = mtu;
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_blocking(vpnsvc_tun_h handle, bool blocking)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ int flags;
+
+ if (tun_s->fd <= 0) {
+ LOGE("The Tunnel File Descriptor fd = %d", tun_s->fd);
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ flags = fcntl(tun_s->fd, F_GETFL);
+ if (flags < 0) {
+ LOGD("File Descriptor Flags GET Failed fd = %d", tun_s->fd);
+ flags = 0;
+ }
+
+ if (blocking == false)
+ flags = flags | O_NONBLOCK;
+ else
+ flags = flags & (~O_NONBLOCK);
+
+ if (fcntl(tun_s->fd, F_SETFL, flags) < 0) {
+ LOGE("Failed fd = %d F_SETFL(flags) = %d", tun_s->fd, flags);
+ return VPNSVC_ERROR_IO_ERROR;
+ }
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_set_session(vpnsvc_tun_h handle, const char* session)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (session == NULL) {
+ LOGE("Session Name string is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ strncpy(tun_s->session, session, VPNSVC_SESSION_STRING_LEN);
+ tun_s->session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+
+ return VPNSVC_ERROR_NONE;
+}
+
+int vpnsvc_get_session(vpnsvc_tun_h handle, char* session)
+{
+ CHECK_FEATURE_SUPPORTED(VPN_SERVICE_FEATURE);
+
+ vpnsvc_tun_s *tun_s = NULL;
+
+ /* parameter check */
+ if (handle == NULL) {
+ LOGE("handle is a NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+ tun_s = (vpnsvc_tun_s*)handle;
+
+ if (session == NULL) {
+ LOGE("Session Name string is NULL");
+ return VPNSVC_ERROR_INVALID_PARAMETER;
+ }
+
+ strncpy(session, tun_s->session, VPNSVC_SESSION_STRING_LEN);
+ session[VPNSVC_SESSION_STRING_LEN-1] = '\0';
+
+ return VPNSVC_ERROR_NONE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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.
+ */
+
+
+#ifndef __TIZEN_COMMON_VPN_ERROR_H__
+#define __TIZEN_COMMON_VPN_ERROR_H__
+
+#include <errno.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup CAPI_COMMON_VPN_ERROR Common VPN Error
+ * @brief This file provides error codes that are common for the whole TIZEN VPN API.
+ * @section CAPI_COMMON_VPN_ERROR_HEADER Required Header
+ * \#include <tizen_vpn_error.h>
+ * @ingroup CAPI_COMMON_ERROR
+ * @{
+ */
+
+#define TIZEN_ERROR_MIN_VPN_ERROR (-268435456) /* = -268435455(0x0FFFFFFF) -1 */
+
+/* Check if slp error or not */
+#define TIZEN_ERROR_IS_VPN_ERROR(x) (TIZEN_ERROR_MIN_VPN_ERROR >= (x) && (x) < 0)
+
+/* Tizen VPN Service Error */
+#define TIZEN_ERROR_VPNSVC -0x10000000
+
+/**
+ * @}
+ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /**<__TIZEN_COMMON_VPN_ERROR_H__ */
--- /dev/null
+/*
+* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+*
+* 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.
+*/
+
+#ifndef __TIZEN_VPN_SERVICE_H__
+#define __TIZEN_VPN_SERVICE_H__
+
+/**
+ * @file vpn_service.h
+ */
+
+/**
+ *@defgroup VPNSVC_FRAMEWORK VPN_SERVICE
+ *@brief The VPN service APIs to manage VPN features such as VPN device (TUN interface) initialization, routing management, DNS management and firewall management.
+ *@section VPNSVC_FRAMEWORK_OVERVIEW Overview
+ * <table>
+ * <tr><th>API</th><th>Description></th></tr>
+ * <tr><td> @ref VPNSVC_FRAMEWORK</td>
+ * <td> Provides functions to vpnsvc_init/vpnsvc_deinit/vpnsvc_protect/vpnsvc_up/vpnsvc_down/vpnsvc_read/vpnsvc_write/vpnsvc_block_networks/vpnsvc_unblock_networks.</td>
+ * </tr></table>
+ **/
+
+#include <tizen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tizen_error.h>
+#include <tizen_vpn_error.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "CAPI_VPNSVC"
+
+#ifndef API
+#define API __attribute__ ((visibility("default")))
+#endif
+
+/**
+ * @brief IPv4 address string length (includes end null character)
+ */
+#define VPNSVC_IP4_STRING_LEN 16
+
+/**
+ * @brief TUN interface name length (IFNAMSIZ)
+ */
+#define VPNSVC_TUN_IF_NAME_LEN 16
+
+/**
+ * @brief Session name string length (includes end null character)
+ */
+#define VPNSVC_SESSION_STRING_LEN 32
+
+
+/**
+ * @brief Enumeration for VPN service error types
+ * @details Indicate formats of error type field
+ * @ingroup VPNSVC_FRAMEWORK
+ */
+typedef enum
+{
+ VPNSVC_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ VPNSVC_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ VPNSVC_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory */
+ VPNSVC_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+ VPNSVC_ERROR_NO_SUCH_FILE = TIZEN_ERROR_NO_SUCH_FILE, /**< No such file or directory */
+ VPNSVC_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< IO error */
+ VPNSVC_ERROR_TIMEOUT = TIZEN_ERROR_TIMED_OUT, /**< Time out error or no answer */
+ VPNSVC_ERROR_IPC_FAILED = TIZEN_ERROR_VPNSVC | 0x02, /**< Failed to communicate with server */
+ VPNSVC_ERROR_LICENSE_FAILED = TIZEN_ERROR_VPNSVC | 0x03, /**< Failed to verify license */
+ VPNSVC_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED /**< Not Supported */
+} vpnsvc_error_e;
+
+
+/**
+ * @brief The structure containing the route information
+ * @details This structure can be used for both vpnsvc_up() and vpnsvc_block_networks() functions.
+ *
+ * @since_tizen 3.0
+ * @see vpnsvc_up()
+ * @see vpnsvc_block_networks()
+ */
+struct vpnsvc_route {
+ char dest[VPNSVC_IP4_STRING_LEN]; /**< Destination address of the route */
+ int prefix; /**< The prefix of route */
+};
+
+/**
+ * @brief The VPN tun interface handle
+ * @details This handle can be obtained by calling vpnsvc_init() and destroyed(NULL) by calling vpnsvc_deinit().
+ * @since_tizen 3.0
+ * @see vpnsvc_init()
+ * @see vpnsvc_deinit()
+ */
+typedef void* vpnsvc_tun_h;
+
+
+/**
+ * @brief Initializes TUN interface (/dev/net/tun)
+ * @detail You should call vpnsvc_get_tun_name() for checking the actual initialized TUN interface name. (In case of duplicated interface name)
+ *
+ * @since_tizen 3.0
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/vpnservicea
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] tun_name The interface name
+ * @param[out] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_PERMISSION_DENIED Permission Denied
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ * @post Please call vpnsvc_deinit() if you want to de-initialize VPN tun interface.
+ * @post Please call vpnsvc_get_tun_fd() if you want to know the fd of tun interface.
+ * @post Please call vpnsvc_get_tun_index() if you want to know the fd of tun interface index(ifr.ifr_ifindex).
+ * @post Please call vpnsvc_get_tun_name() if you want to know the name of tun interface(ifr.ifr_name).
+ * @see vpnsvc_deinit()
+ * @see vpnsvc_get_tun_fd()
+ * @see vpnsvc_get_tun_index()
+ * @see vpnsvc_get_tun_name()
+ */
+API int vpnsvc_init(const char* tun_name, vpnsvc_tun_h *handle);
+
+/**
+ * @brief De-Initializes TUN interface
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_deinit(vpnsvc_tun_h handle);
+
+/**
+ * @brief Prevents the underlying VPN traffic to be routed to the VPN itself
+ * @details The specific socket will be bound to the network interface using by this function.
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] socket_fd The opened socket file descriptor
+ * @param[in] dev_name The network interface name (i.e. eth0 or ppp0, not to confuse with tunXXX) through which the VPN is working
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ */
+API int vpnsvc_protect(vpnsvc_tun_h handle, int socket_fd, const char* dev_name);
+
+/**
+ * @brief Sets-up TUN interface and brings it up. Installs specified routes/DNS servers/DNS suffix
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] local_ip The local IP address
+ * @param[in] remote_ip The remote IP address
+ * @param[in] routes The list of routes for applying to routing table (see vpnsvc_route struct) - Optional
+ * @param[in] nr_routes The number of routes - Optional
+ * @param[in] dns_servers The list of DNS server names - Optional
+ * @param[in] nr_dns_servers The number of DNS server names - Optional
+ * @param[in] dns_suffix The DNS suffix - Optional
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre The VPN tun interface should be initialized already.
+ * @post If you want to set interface down, please call vpnsvc_down().
+ * @see #vpnsvc_route
+ * @see vpnsvc_init()
+ * @see vpnsvc_down()
+ */
+API int vpnsvc_up(vpnsvc_tun_h handle, const char* local_ip, const char* remote_ip,
+ const struct vpnsvc_route* routes, size_t nr_routes,
+ const char** dns_servers, size_t nr_dns_servers,
+ const char* dns_suffix);
+
+/**
+ * @brief Brings the TUN interface down and restores original DNS servers/domains
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API.
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre The VPN tun interface should be initialized already.
+ * @post Please call vpnsvc_deinit() if you want to de-initialize VPN tun interface.
+ * @see vpnsvc_up()
+ * @see vpnsvc_deinit()
+ */
+API int vpnsvc_down(vpnsvc_tun_h handle);
+
+/**
+ * @brief Waits for the read event on TUN descriptor, but no more than the indicated timeout in milliseconds
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] timeout_ms The value of timeout (milliseconds)
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR I/O Error (e.g. socket I/O error)
+ * @retval #VPNSVC_ERROR_TIMEOUT Timeout (no answer in timeout_ms)
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre The VPN interface should be initialized already.
+ * @see vpnsvc_init()
+ * @see vpnsvc_up()
+ */
+API int vpnsvc_read(vpnsvc_tun_h handle, int timeout_ms);
+
+/**
+ * @brief Writes the data supplied into the TUN interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] data Data writing to tun interface
+ * @param[in] size The size of data
+ *
+ * @return On success, the number of bytes written is returned (zero indicates nothing was written). Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ * @retval In case of negative error, please refer to standard posix write API's error code.
+ *
+ * @pre The VPN interface should be initialized already.
+ * @see vpnsvc_init()
+ * @see vpnsvc_up()
+ */
+API int vpnsvc_write(vpnsvc_tun_h handle, const char* data, size_t size);
+
+/**
+ * @brief Blocks all traffics except specified allowing networks
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] allow_routes_vpn The list of allowing networks over VPN interface (Please see vpnsvc_route structure).
+ * @param[in] nr_allow_routes_vpn The number of allowing networks over VPN interface
+ * @param[in] allow_routes_orig The list of allowing networks over the original interface (Please see vpnsvc_route structure).
+ * @param[in] nr_allow_routes_orig The number of allowing networks over the original interface
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @post Please call vpnsvc_unblock_networks() if you want to allow all traffics.
+ * @see vpnsvc_unblock_networks()
+ */
+API int vpnsvc_block_networks(vpnsvc_tun_h handle,
+ const struct vpnsvc_route* allow_routes_vpn,
+ size_t nr_allow_routes_vpn,
+ const struct vpnsvc_route* allow_routes_orig,
+ size_t nr_allow_routes_orig);
+
+/**
+ * @brief Removes any restrictions imposed by vpnsvc_block_networks()
+ *
+ * @since_tizen 3.0
+ * @remarks The license needed if you want to use this VPN API
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return 0 on success. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_IPC_FAILED Cannot connect to service daemon
+ * @retval #VPNSVC_ERROR_LICENSE_FAILED Failed to verify license
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ */
+API int vpnsvc_unblock_networks(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the fd of the VPN tun interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return The fd value of VPN tun interface. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ */
+API int vpnsvc_get_tun_fd(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the index of VPN tun interface (if.if_index)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ *
+ * @return The index of the VPN tun interface. otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_tun_index(vpnsvc_tun_h handle);
+
+/**
+ * @brief Gets the name of VPN tun interface (if.if_name)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[out] tun_name The name of VPN tun interface name
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_tun_name(vpnsvc_tun_h handle, char* tun_name);
+
+/**
+ * @brief Sets the MTU of the VPN tun interface (if.if_name)
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] mtu The MTU (Maximum Transmission Unit) value to be set for VPN tun interface. Default MTU size is 1500.
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_mtu(vpnsvc_tun_h handle, int mtu);
+
+/**
+ * @brief Sets blocking mode of the file descriptor of VPN tun interface
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] blocking The blocking mode flag; True = BLOCKING, False = NON_BLOCKING
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_IO_ERROR Failed to set the blocking flags
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_blocking(vpnsvc_tun_h handle, bool blocking);
+
+/**
+ * @brief Sets the session name for the VPN
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[in] session The Session Name
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_set_session(vpnsvc_tun_h handle, const char* session);
+
+/**
+ * @brief Gets the session name for the VPN
+ *
+ * @since_tizen 3.0
+ *
+ * @param[in] handle The VPN tun interface handle
+ * @param[out] session The Session Name returned
+ *
+ * @return 0 on success. Otherwise, a negative error value.
+ * @retval #VPNSVC_ERROR_NONE Success
+ * @retval #VPNSVC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #VPNSVC_ERROR_NOT_SUPPORTED Not Supported
+ *
+ * @pre Before calling this function, VPN tun interface should be initialized already.
+ * @see vpnsvc_init()
+ */
+API int vpnsvc_get_session(vpnsvc_tun_h handle, char* session);
+
+#endif /* __TIZEN_CAPI_VPN_SERVICE_H__ */
--- /dev/null
+Name: vpnsvc-pkg
+Summary: VPN service library in TIZEN C API
+Version: 1.0.5
+Release: 1
+Group: System/Network
+License: Apache License, Version 2.0
+URL: N/A
+Source0: %{name}-%{version}.tar.gz
+Source1: vpnsvc-daemon.service
+Source2: org.tizen.vpnsvc.service
+BuildRequires: cmake
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(dbus-glib-1)
+BuildRequires: pkgconfig(dbus-1)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-appfw-package-manager)
+BuildRequires: pkgconfig(capi-appfw-app-manager)
+BuildRequires: pkgconfig(capi-system-info)
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description
+capi-vpn-service framework, service
+
+%package -n capi-vpnsvc
+Summary: VPN service library in TIZEN C API
+Group: Development/Libraries
+#Requires: capi-vpnsvc
+
+%description -n capi-vpnsvc
+capi-vpnsvc CAPI package
+
+%package -n capi-vpnsvc-devel
+Summary: VPN service library in TIZEN C API (Development)
+Group: Development/Libraries
+
+%description -n capi-vpnsvc-devel
+capi-vpnsvc CAPI devel package
+
+%package -n vpnsvc-test
+Summary: Vpnsvc test
+Group: Development/Libraries
+
+%description -n vpnsvc-test
+vpnsvc test package
+
+%package -n vpnsvc-daemon
+Summary: Vpnsvc daemon
+Group: Development/Libraries
+Requires: systemd
+Requires(preun): systemd
+Requires(post): systemd
+Requires(postun): systemd
+
+%description -n vpnsvc-daemon
+vpnsvc daemon package
+
+%prep
+%setup -q
+
+%build
+%if 0%{?sec_build_binary_debug_enable}
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+%endif
+
+%if 0%{?tizen_build_binary_release_type_eng}
+export CFLAGS="$CFLAGS -DTIZEN_ENGINEER_MODE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_ENGINEER_MODE"
+export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE"
+%endif
+
+export LDFLAGS+="-Wl,--rpath=%{_libdir}"
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake . -DVERSION=%{version} \
+ -DFULLVER=%{version} \
+ -DMAJORVER=${MAJORVER} \
+ -DCMAKE_BUILD_TYPE=%{?build_type:%build_type}%{!?build_type:RELEASE} \
+ -DTIZEN_ENGINEER_MODE=%{?tizen_build_binary_release_type_eng:1}%{!?tizen_build_binary_release_type_eng:0} \
+ -DCMAKE_VERBOSE_MAKEFILE=ON
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+
+mkdir -p %{buildroot}/%{_datadir}/license
+cp LICENSE-Apache.v2.0 %{buildroot}/%{_datadir}/license/capi-vpnsvc
+#cp LICENSE.APLv2 %{buildroot}/usr/share/license/fpasmtztransport
+
+%make_install
+mkdir -p %{buildroot}%{_libdir}/systemd/system
+install -m 0644 %{SOURCE1} %{buildroot}%{_libdir}/systemd/system/vpnsvc-daemon.service
+mkdir -p %{buildroot}%{_datadir}/dbus-1/system-services
+install -m 0644 %{SOURCE2} %{buildroot}%{_datadir}/dbus-1/system-services/org.tizen.vpnsvc.service
+
+%clean
+rm -rf %{buildroot}
+
+%post -n capi-vpnsvc
+ln -s %{_libdir}/libcapi-vpnsvc.so.0 %{_libdir}/libcapi-vpnsvc.so
+
+%postun
+if [ $1 == 0 ]; then
+ # unistall
+ systemctl daemon-reload
+fi
+
+%files -n vpnsvc-daemon
+%manifest daemon/vpnsvc-daemon.manifest
+%attr(0755,root,root) %{_bindir}/vpnsvc-daemon
+%defattr(-,root,root,-)
+%{_libdir}/systemd/system/vpnsvc-daemon.service
+%{_datadir}/dbus-1/system-services/org.tizen.vpnsvc.service
+
+%files -n capi-vpnsvc
+%manifest framework/capi-vpnsvc.manifest
+%{_libdir}/libcapi-vpnsvc.so.*
+%{_datadir}/license/capi-vpnsvc
+
+%files -n capi-vpnsvc-devel
+%{_includedir}/*.h
+%{_libdir}/pkgconfig/capi-vpnsvc.pc
+%{_libdir}/libcapi-vpnsvc.so
+
+%files -n vpnsvc-test
+%manifest test/vpnsvc-test.manifest
+/usr/sbin/vpnsvc-test
+
--- /dev/null
+[D-BUS Service]
+Name=org.tizen.vpnsvc
+Exec=/bin/false
+User=root
+Group=root
+SystemdService=vpnsvc-daemon.service
+
--- /dev/null
+[Unit]
+Description=Start vpn-service-daemon for vpn-service
+
+[Service]
+User=root
+Group=root
+SmackProcessLabel=vpnsvc
+Type=dbus
+BusName=org.tizen.vpnsvc
+RemainAfterExit=yes
+ExecStart=/usr/bin/vpnsvc-daemon
+Restart=always
+RestartSec=0
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(PACKAGE_NAME vpnsvc-test)
+SET(LIB_NAME ${PACKAGE_NAME})
+PROJECT(${LIB_NAME})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(EXEC_PREFIX "\${prefix}")
+SET(LIBDIR "\${prefix}/lib")
+SET(INCLUDEDIR "\${prefix}/include")
+SET(VERSION 0.1)
+
+SET(TEST_ROOT "${CMAKE_SOURCE_DIR}/test")
+
+SET(requires "dlog dbus-glib-1 capi-base-common capi-appfw-application")
+SET(pc_requires "capi-base-common")
+
+SET(TEST_SRCS
+ vpn_service_test.c)
+
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/framework/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${PACKAGE_NAME} REQUIRED ${requires})
+FOREACH(flag ${${PACKAGE_NAME}_CFLAGS})
+ SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+# Compiler flags
+SET(EXTRA_C_FLAGS "${EXTRA_CFLAGS} -fPIC -Wall -fvisibility=hidden")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_C_FLAGS}")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+
+ADD_DEFINITIONS("-DSLP_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+ADD_EXECUTABLE(${PACKAGE_NAME} ${TEST_SRCS})
+TARGET_LINK_LIBRARIES(${PACKAGE_NAME} ${${PACKAGE_NAME}_LDFLAGS} "-ldl" capi-vpnsvc)
+
+INSTALL(TARGETS ${PACKAGE_NAME} DESTINATION sbin)
--- /dev/null
+/*
+ * VPN Service Module
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+
+#include "capi_vpn_service_private.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "VPNSVC_TEST"
+
+#define TEST_VPN_IF_NAME "vpnsvc_test"
+
+#define TEST_CONSOLE_PRINT(FMT, ARG...) fprintf(stderr, FMT, ##ARG); \
+ fprintf(stderr, "\n")
+#define TEST_CONSOLE_INPUT(BUFFER, LENGTH) \
+ do {\
+ if (fgets(BUFFER, sizeof BUFFER, stdin) == NULL) \
+ perror("fgets() failed!!!");\
+ } while (0);
+
+vpnsvc_tun_h handle = NULL;
+
+int test_vpnsvc_init()
+{
+ char *name = TEST_VPN_IF_NAME;
+ int ret = VPNSVC_ERROR_NONE;
+
+ printf("test vpnsvc_init\n");
+
+ ret = vpnsvc_init(name, &handle);
+
+ if (ret != VPNSVC_ERROR_NONE) {
+ printf("vpnsvc_init failed : %d\n", ret);
+ } else {
+ char result_name[VPNSVC_TUN_IF_NAME_LEN] = {0, };
+ printf("vpnsvc_init Succeed : %d\n", ret);
+
+ printf("tun_fd : %d\n", vpnsvc_get_tun_fd(handle));
+ printf("tun_index : %d\n", vpnsvc_get_tun_index(handle));
+ ret = vpnsvc_get_tun_name(handle, result_name);
+ if (ret == VPNSVC_ERROR_NONE)
+ printf("tun_name : %s\n", result_name);
+ }
+
+ return 0;
+}
+
+int test_vpnsvc_deinit()
+{
+ printf("test vpnsvc_deinit\n");
+
+ if (handle)
+ vpnsvc_deinit(handle);
+
+ handle = NULL;
+
+ return 0;
+
+}
+
+int test_vpnsvc_protect()
+{
+ int sock, ret;
+
+ printf("test vpnsvc_protect\n");
+
+ if (!handle) {
+ printf("invalid handle\n");
+ return -1;
+ }
+
+ if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+ printf("socket failed\n");
+ return -2;
+ }
+
+ ret = vpnsvc_protect(handle, sock, "wlan0");
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_protect failed!\n");
+ else
+ printf("vpnsvc_protect Succeed!\n");
+
+ close(sock);
+
+ return 0;
+}
+
+int test_vpnsvc_up()
+{
+ int ret;
+ char local[VPNSVC_IP4_STRING_LEN] = {'\0',};
+ char remote[VPNSVC_IP4_STRING_LEN] = {'\0',};
+ struct vpnsvc_route routes[2];
+ int nr_routes = 2;
+ const char *dns_server[2];
+ int nr_dns = 2;
+ char dns_suffix[100] = "tizen.org";
+
+ if (!handle) {
+ printf("invalid handle\n");
+ return -1;
+ }
+
+ strncpy(local, "192.168.0.82", VPNSVC_IP4_STRING_LEN);
+ strncpy(remote, "192.168.0.1", VPNSVC_IP4_STRING_LEN);
+
+ memset(routes, 0, sizeof(routes));
+ strncpy(routes[0].dest, "192.168.0.10", VPNSVC_IP4_STRING_LEN);
+ routes[0].prefix = 32;
+ strncpy(routes[1].dest, "192.168.0.11", VPNSVC_IP4_STRING_LEN);
+ routes[1].prefix = 32;
+
+ char *dns1 = "1.1.1.1";
+ char *dns2 = "2.2.2.2";
+
+ dns_server[0] = dns1;
+ dns_server[1] = dns2;
+
+ ret = vpnsvc_up(handle, local, remote, routes, nr_routes, dns_server, nr_dns, dns_suffix);
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_up failed!\n");
+ else
+ printf("vpnsvc_up Succeed!\n");
+
+ return 0;
+}
+
+int test_vpnsvc_down()
+{
+ int ret;
+
+ if (!handle) {
+ printf("invalid handle\n");
+ return -1;
+ }
+
+ ret = vpnsvc_down(handle);
+
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_down failed!\n");
+ else
+ printf("vpnsvc_down Succeed!\n");
+
+ return 0;
+
+}
+
+int test_vpnsvc_read()
+{
+ return 0;
+}
+
+int test_vpnsvc_write()
+{
+ return 0;
+}
+
+int test_vpnsvc_block_networks()
+{
+ struct vpnsvc_route block_nets[2];
+ int block_nr_nets = 2;
+ struct vpnsvc_route allow_nets[2];
+ int allow_nr_nets = 2;
+ int ret;
+
+ if (!handle) {
+ printf("invalid handle\n");
+ return -1;
+ }
+
+ memset(block_nets, 0, sizeof(block_nets));
+ strncpy(block_nets[0].dest, "125.209.222.141", VPNSVC_IP4_STRING_LEN);
+ block_nets[0].prefix = 32;
+ strncpy(block_nets[1].dest, "180.70.134.19", VPNSVC_IP4_STRING_LEN);
+ block_nets[1].prefix = 32;
+
+ memset(allow_nets, 0, sizeof(allow_nets));
+ strncpy(allow_nets[0].dest, "216.58.221.142", VPNSVC_IP4_STRING_LEN); /* google.com */
+ allow_nets[0].prefix = 32;
+ strncpy(allow_nets[1].dest, "206.190.36.45", VPNSVC_IP4_STRING_LEN); /* yahoo.com */
+ allow_nets[1].prefix = 32;
+
+ ret = vpnsvc_block_networks(handle, block_nets, block_nr_nets, allow_nets, allow_nr_nets);
+
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_block_networks failed!\n");
+ else
+ printf("vpnsvc_block_networks Succeed!\n");
+
+ return 0;
+
+}
+
+int test_vpnsvc_unblock_networks()
+{
+ int ret;
+
+ if (!handle) {
+ printf("invalid handle\n");
+ return -1;
+ }
+
+ ret = vpnsvc_unblock_networks(handle);
+
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_unblock_networks failed!\n");
+ else
+ printf("vpnsvc_unblock_networks Succeed!\n");
+
+ return 0;
+}
+
+int test_vpnsvc_set_mtu()
+{
+ int ret;
+
+ ret = vpnsvc_set_mtu(handle, 9000);
+
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_set_mtu failed!\n");
+ else
+ printf("vpnsvc_set_mtu Succeed!\n");
+
+ return 0;
+}
+
+bool g_blocking = false;
+
+int test_vpnsvc_set_blocking()
+{
+ int ret;
+ g_blocking = !g_blocking;
+
+ printf("Blocking Parameter: %s\n", g_blocking ? "true" : "false");
+ ret = vpnsvc_set_blocking(handle, g_blocking);
+
+ if (ret != VPNSVC_ERROR_NONE)
+ printf("vpnsvc_set_blocking failed!\n");
+ else
+ printf("vpnsvc_set_blocking Succeed!\n");
+
+ return 0;
+}
+
+int test_vpnsvc_set_session()
+{
+ int ret;
+ char *set_session = "vpnsvc_test VPN Session";
+ char get_session[VPNSVC_SESSION_STRING_LEN];
+
+ ret = vpnsvc_set_session(handle, set_session);
+
+ if (ret != VPNSVC_ERROR_NONE) {
+ printf("vpnsvc_set_session failed!\n");
+ } else {
+ ret = vpnsvc_get_session(handle, get_session);
+ printf("Session Name = %s\n", get_session);
+ printf("vpnsvc_set_session Succeed!\n");
+ }
+
+ return 0;
+}
+
+int test_exit()
+{
+ exit(0);
+}
+
+
+int (*test_function_table[])(void) = {
+ test_vpnsvc_init,
+ test_vpnsvc_deinit,
+ test_vpnsvc_protect,
+ test_vpnsvc_up,
+ test_vpnsvc_down,
+ test_vpnsvc_read,
+ test_vpnsvc_write,
+ test_vpnsvc_block_networks,
+ test_vpnsvc_unblock_networks,
+ test_vpnsvc_set_mtu,
+ test_vpnsvc_set_blocking,
+ test_vpnsvc_set_session,
+ test_exit,
+};
+
+int main()
+{
+ char input[3] = {0,};
+
+ printf("capi_vpn_service test\n");
+ while (1) {
+ __fpurge(stdin);
+ printf("1 : vpnsvc_init\n");
+ printf("2 : vpnsvc_deinit\n");
+ printf("3 : vpnsvc_protect\n");
+ printf("4 : vpnsvc_up\n");
+ printf("5 : vpnsvc_down\n");
+ printf("6 : vpnsvc_read\n");
+ printf("7 : vpnsvc_write\n");
+ printf("8 : vpnsvc_block_networks\n");
+ printf("9 : vpnsvc_unblock_networks\n");
+ printf("10 : vpnsvc_set_mtu\n");
+ printf("11 : vpnsvc_set_blocking\n");
+ printf("12 : vpnsvc_set_session\n");
+ printf("q : quit\n");
+
+ TEST_CONSOLE_INPUT(input, 3);
+ unsigned int comm = strtoul(input, NULL, 0);
+ if (comm <= 0 || comm > (sizeof(test_function_table) / sizeof(int))) {
+ if (input[0] == 'q') {
+ test_exit();
+ return 0;
+ }
+
+ printf("Invalid index. Retry\n");
+ continue;
+ }
+
+ test_function_table[comm-1]();
+ }
+ return 0;
+}
--- /dev/null
+<manifest>
+ <define>
+ <domain name="vpnsvc_test"/>
+ <permit>
+ <smack permit="sdbd" type="rwxat"/>
+ <smack permit="dbus" type="rw"/>
+ </permit>
+ <request>
+ <smack request="vpnsvc::tun" type="rw"/>
+ <smack request="vpnsvc::protect" type="rw"/>
+ <smack request="vpnsvc::interface" type="rw"/>
+ <smack request="vpnsvc::block_networks" type="rw"/>
+ <smack request="device::app_logging" type="w"/>
+ <smack request="device::sys_logging" type="w"/>
+ <smack request="sdbd" type="rwxat"/>
+ </request>
+ </define>
+ <assign>
+ <filesystem path="/usr/sbin/vpnsvc-test" label="vpnsvc_test" exec_label="vpnsvc_test"/>
+ </assign>
+ <request>
+ <domain name="vpnsvc_test"/>
+ </request>
+</manifest>