From a1d936e3b50ff0a8c3fd91f57b9db5ce86fcf6a2 Mon Sep 17 00:00:00 2001 From: Jaehyun Kim Date: Tue, 7 Sep 2021 14:59:37 +0900 Subject: [PATCH] Add plugin for online monitoring Change-Id: Ic96e513404635c869e18aba870e040418705d457 Signed-off-by: Jaehyun Kim --- CMakeLists.txt | 6 + include/network-state.h | 2 + include/plugin.h | 6 + include/util.h | 1 + packaging/net-config.spec | 28 +- plugin/online-monitor/CMakeLists.txt | 43 ++ plugin/online-monitor/online-monitor.c | 467 ++++++++++++++++++++++ plugin/online-monitor/online-monitor.h | 80 ++++ plugin/online-monitor/online_monitor.conf | 8 + plugin/online-monitor/report-manager.c | 40 ++ plugin/online-monitor/url-checker.c | 40 ++ src/network-state.c | 24 ++ src/signal-handler.c | 7 +- src/utils/util.c | 62 ++- 14 files changed, 800 insertions(+), 14 deletions(-) create mode 100755 plugin/online-monitor/CMakeLists.txt create mode 100755 plugin/online-monitor/online-monitor.c create mode 100644 plugin/online-monitor/online-monitor.h create mode 100644 plugin/online-monitor/online_monitor.conf create mode 100755 plugin/online-monitor/report-manager.c create mode 100755 plugin/online-monitor/url-checker.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 50a546f..b5646be 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) PROJECT(net-config C CXX) SET(PACKAGE ${PROJECT_NAME}) SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(INCDIR "${PREFIX}/include") SET(BINDIR "${PREFIX}/bin") SET(DATADIR "${PREFIX}/share") SET(LIBDIR "${PREFIX}/${LIB_PATH}") @@ -69,6 +70,10 @@ IF(TIZEN_CAPTIVE_PORTAL) SET(SRCS ${SRCS} src/utils/network-accessibility.c) ENDIF(TIZEN_CAPTIVE_PORTAL) +IF(TIZEN_ARCH_64) + ADD_DEFINITIONS(-DTIZEN_ARCH_64) +ENDIF(TIZEN_ARCH_64) + IF(TIZEN_WEARABLE) ADD_DEFINITIONS(-DTIZEN_WEARABLE) ENDIF(TIZEN_WEARABLE) @@ -139,6 +144,7 @@ ADD_SUBDIRECTORY(plugin/headed) ADD_SUBDIRECTORY(plugin/telephony) ADD_SUBDIRECTORY(plugin/stc) ADD_SUBDIRECTORY(plugin/battery) +ADD_SUBDIRECTORY(plugin/online-monitor) ADD_SUBDIRECTORY(haltests) IF(BUILD_GTESTS) ADD_SUBDIRECTORY(gtest) diff --git a/include/network-state.h b/include/network-state.h index 40853a0..b7bff2c 100755 --- a/include/network-state.h +++ b/include/network-state.h @@ -35,10 +35,12 @@ const char *netconfig_get_default_mac_address(void); unsigned int netconfig_get_default_frequency(void); const char *netconfig_wifi_get_connected_essid(const char *default_profile); gboolean netconfig_get_default_is_metered(void); +gboolean netconfig_get_default_is_internet(void); void netconfig_set_default_ipaddress(const char *ipaddr); void netconfig_set_default_ipaddress6(const char *ipaddr); void netconfig_set_default_proxy(const char *proxy); +void netconfig_set_default_is_internet(gboolean state); void netconfig_update_default(void); void netconfig_update_default_profile(void); diff --git a/include/plugin.h b/include/plugin.h index 8c92136..885dca0 100755 --- a/include/plugin.h +++ b/include/plugin.h @@ -168,6 +168,12 @@ struct netconfig_bm_plugin_t { int (*get_feature_data) (bm_data_h *, bm_plugin_data_type_e); }; +struct netconfig_online_monitor_plugin_t { + int (*init) (void); + int (*deinit) (void); + int (*notify_online_state) (char *, gboolean); +}; + typedef enum { SYS_EVT_NETWORK_STATUS = 0, SYS_EVT_WIFI_STATE = 1, diff --git a/include/util.h b/include/util.h index 73f41c5..09e4359 100755 --- a/include/util.h +++ b/include/util.h @@ -132,6 +132,7 @@ void netconfig_plugin_init(); void netconfig_plugin_deinit(); gboolean netconfig_get_headed_plugin_flag(); gboolean netconfig_get_telephony_plugin_flag(); +void netconfig_notify_online_state(char *ifname, gboolean online_state); void netconfig_convert_bytes_to_hexstr(const char* bin, int blen, gchar* hexstr); diff --git a/packaging/net-config.spec b/packaging/net-config.spec index 817f96f..51ce1fa 100755 --- a/packaging/net-config.spec +++ b/packaging/net-config.spec @@ -1,7 +1,7 @@ Name: net-config Summary: TIZEN Network Configuration service -Version: 1.2.10 -Release: 3 +Version: 1.2.11 +Release: 1 Group: System/Network License: Apache-2.0 Source0: %{name}-%{version}.tar.gz @@ -96,6 +96,15 @@ Requires: %{name} = %{version}-%{release} %description haltests TIZEN Network Configuration service extension for HAL test. +%package plugin-online-monitor +Summary: net-config extension for advanced online monitoring +BuildRequires: connman-extension-bpf-devel +Requires: libelf0 +Requires: connman-extension-bpf +Requires: %{name} = %{version}-%{release} +%description plugin-online-monitor +TIZEN Network Configuration service extension for advanced online monitoring. + %prep %setup -q @@ -107,6 +116,9 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DTIZEN_DEBUG_ENABLE=0 \ -DTIZEN_WEARABLE=1 \ -DTIZEN_CAPTIVE_PORTAL=1 \ +%if "%{?_lib}" == "lib64" + -DTIZEN_ARCH_64=1 \ +%endif -DLIB_PATH=%{_lib} \ -DBIN_DIR=%{_bindir} \ -DBUILD_GTESTS=%{?gtests:1}%{!?gtests:0} \ @@ -126,6 +138,9 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ -DTIZEN_DEBUG_ENABLE=0 \ -DTIZEN_WEARABLE=0 \ -DTIZEN_CAPTIVE_PORTAL=0 \ +%if "%{?_lib}" == "lib64" + -DTIZEN_ARCH_64=1 \ +%endif -DLIB_PATH=%{_lib} \ -DBIN_DIR=%{_bindir} \ -DBUILD_GTESTS=%{?gtests:1}%{!?gtests:0} \ @@ -134,7 +149,6 @@ cmake -DCMAKE_INSTALL_PREFIX=%{_prefix} \ make %{?_smp_mflags} - %install %make_install @@ -181,6 +195,9 @@ cp resources/usr/system/RestoreDir/softreset/network_softreset.sh %{buildroot}/u mv %{_builddir}/%{name}-%{version}/net-config.wearable %{buildroot}%{_bindir} +#online-monitor +cp plugin/online-monitor/online_monitor.conf %{buildroot}/%{_localstatedir}/lib/net-config + %post chsmack -a 'System::Shared' %{_sysconfdir}/resolv.conf chsmack -a 'System::Shared' %{TZ_SYS_ETC}/resolv.conf @@ -267,3 +284,8 @@ mv /var/lib/net-config/settings-robot /var/lib/net-config/settings %files haltests %manifest net-config.manifest %{_bindir}/hal/*haltests + +%files plugin-online-monitor +%manifest net-config.manifest +%attr(500,network_fw,network_fw) %{_libdir}/net-config-plugin-online-monitor.so +%attr(644,root,root) %{_localstatedir}/lib/net-config/online_monitor.conf diff --git a/plugin/online-monitor/CMakeLists.txt b/plugin/online-monitor/CMakeLists.txt new file mode 100755 index 0000000..3d3652b --- /dev/null +++ b/plugin/online-monitor/CMakeLists.txt @@ -0,0 +1,43 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(net-config-plugin-online-monitor C) + +IF(TIZEN_WEARABLE) + ADD_DEFINITIONS(-DTIZEN_WEARABLE) +ENDIF(TIZEN_WEARABLE) + +ADD_DEFINITIONS(-DUSE_NETCONFIG_LOG) + +# Set required packages +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(pkgs_online_mon REQUIRED + dlog + glib-2.0 + ) + +FOREACH(flag ${pkgs_online_mon_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/include + ${INCDIR}/bpf +) +# INCLUDE_DIRECTORIES(SRCS include) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -g -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") +SET(CMAKE_C_FLAGS_RELEASE "-O2") + +SET(SRCS_ONLINE_MON + online-monitor.c + url-checker.c + report-manager.c + ) + +# library build +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS_ONLINE_MON}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_online_mon_LDFLAGS} "-lbpf") +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES PREFIX "" OUTPUT_NAME ${PROJECT_NAME}) + +# install +INSTALL(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${LIBDIR}) diff --git a/plugin/online-monitor/online-monitor.c b/plugin/online-monitor/online-monitor.c new file mode 100755 index 0000000..b2bde47 --- /dev/null +++ b/plugin/online-monitor/online-monitor.c @@ -0,0 +1,467 @@ +/* + * Network Configuration Module + * + * Copyright (c) 2021 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "online-monitor.h" + +#define BPF_FILE_PATH "/var/lib/connman/bpf_code" +#define BPF_MAP_INTERVAL 3 +#define DNS_NO_RESPONSE_MAX 4 +#define DETECTION_INTERVAL 4 + +static struct { + struct bpf_object *obj; + int prog_fd; + int map_fd; + int sock; + int timer; +} bpf_info; + +static struct { + __u32 unreachable; + __u32 dns_query; + __u32 dns_response; + __u32 dns_refused; + __u32 no_response_count; + __u32 detection_interval_count; +} bpf_map_info; + +static GSList *notifier_list = NULL; +static char def_ifname[32] = {0, }; +static online_monitor_state_e g_state = ONLINE_MONITOR_STATE_UNINITIALIZED; +static online_monitor_config_t online_monitor_config; + +static void stop_monitoring(void); + +static int open_raw_socket(const char *ifname) +{ + struct sockaddr_ll sock_ll; + int sock; + + sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL)); + if (sock < 0) { + ERR("raw socket creation failed\n"); + return -1; + } + + memset(&sock_ll, 0, sizeof(sock_ll)); + sock_ll.sll_family = AF_PACKET; + sock_ll.sll_ifindex = if_nametoindex(ifname); + sock_ll.sll_protocol = htons(ETH_P_ALL); + + if (bind(sock, (struct sockaddr *)&sock_ll, sizeof(sock_ll)) < 0) { + ERR("bind failed, ifname %s error %s\n", ifname, strerror(errno)); + close(sock); + return -1; + } + + return sock; +} + +static void notify_monitoring_state(online_monitor_state_e state, online_monitor_detection_e reason) +{ + GSList *list; + + DBG("state %d, ifname %s, reason %d", state, def_ifname, reason); + + for (list = notifier_list; list; list = list->next) { + const online_monitor_state_chaged_cb notifier = list->data; + + if (notifier) + notifier(state, def_ifname, reason); + } +} + +static gboolean check_bpf_map(gpointer data) +{ + __u32 unreachable = 0; + __u32 dns_query = 0; + __u32 dns_response = 0; + __u32 dns_refused = 0; + __u32 key; + gboolean detected = FALSE; + gboolean skip_detection = FALSE; + online_monitor_detection_e reason = ONLINE_MONITOR_DETECTION_NONE; + + if (g_state == ONLINE_MONITOR_STATE_OFFLINE_DETECTED) + return TRUE; + + if (g_state == ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED) { + if (bpf_map_info.detection_interval_count < DETECTION_INTERVAL) { + bpf_map_info.detection_interval_count++; + return TRUE; + } else { + bpf_map_info.detection_interval_count = 0; + g_state = ONLINE_MONITOR_STATE_MONITORING_STARTED; + skip_detection = TRUE; + } + } + + key = 1; + if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &unreachable) != 0) { + ERR("Failed to get unreachable count from bpf map"); + bpf_info.timer = 0; + return FALSE; + } + + key = 2; + if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_query) != 0) { + ERR("Failed to get dns_query count from bpf map"); + bpf_info.timer = 0; + return FALSE; + } + + key = 3; + if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_response) != 0) { + ERR("Failed to get dns_response count from bpf map"); + bpf_info.timer = 0; + return FALSE; + } + + key = 4; + if (bpf_map_lookup_elem(bpf_info.map_fd, &key, &dns_refused) != 0) { + ERR("Failed to get dns_refused count from bpf map"); + bpf_info.timer = 0; + return FALSE; + } + + DBG("unreachable %u dns_query %u dns_response %u dns_refused %u", + unreachable, dns_query, dns_response, dns_refused); + + if (skip_detection) { + skip_detection = FALSE; + goto update; + } + + if (bpf_map_info.unreachable < unreachable) { + detected = TRUE; + reason = ONLINE_MONITOR_DETECTION_UNREACHABLE; + } else if (bpf_map_info.dns_refused < dns_refused) { + detected = TRUE; + reason = ONLINE_MONITOR_DETECTION_DNS_REFUSED; + } else if (bpf_map_info.no_response_count == 0 + && bpf_map_info.dns_query < dns_query + && bpf_map_info.dns_response == dns_response) { + bpf_map_info.no_response_count++; + } else if (bpf_map_info.no_response_count > 0) { + if (bpf_map_info.dns_response == dns_response) + bpf_map_info.no_response_count++; + else + bpf_map_info.no_response_count = 0; + + if (bpf_map_info.no_response_count > DNS_NO_RESPONSE_MAX) { + detected = TRUE; + reason = ONLINE_MONITOR_DETECTION_NO_DNS_RESPONSE; + } + } + + if (detected) { + bpf_map_info.no_response_count = 0; + g_state = ONLINE_MONITOR_STATE_OFFLINE_DETECTED; + notify_monitoring_state(ONLINE_MONITOR_STATE_OFFLINE_DETECTED, reason); + } + +update: + bpf_map_info.unreachable = unreachable; + bpf_map_info.dns_query = dns_query; + bpf_map_info.dns_response = dns_response; + bpf_map_info.dns_refused = dns_refused; + + return TRUE; +} + +void online_monitor_url_check_result(gboolean result) +{ + DBG("url_check result %s", result ? "TRUE" : "FALSE"); + + if (result) { + notify_monitoring_state(ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED, ONLINE_MONITOR_DETECTION_NONE); + g_state = ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED; + } else { + notify_monitoring_state(ONLINE_MONITOR_STATE_URL_CHECK_FAILED, ONLINE_MONITOR_DETECTION_NONE); + g_state = ONLINE_MONITOR_STATE_URL_CHECK_FAILED; + stop_monitoring(); + } +} + +void online_monitor_notifier_register(online_monitor_state_chaged_cb notifier) +{ + DBG("notifier %p", notifier); + + notifier_list = g_slist_prepend(notifier_list, (void*)notifier); +} + +void online_monitor_notifier_unregister(online_monitor_state_chaged_cb notifier) +{ + DBG("notifier %p", notifier); + + notifier_list = g_slist_remove(notifier_list, notifier); +} + +online_monitor_config_t *online_monitor_get_configuration(void) +{ + return &online_monitor_config; +} + +static void start_monitoring(void) +{ + int rv = 0; + char bpf_file[256]; + + if (def_ifname[0] == 0) + return; + + if (g_state != ONLINE_MONITOR_STATE_MONITORING_STOPPED + && g_state != ONLINE_MONITOR_STATE_INITIALIZED + && g_state != ONLINE_MONITOR_STATE_UNINITIALIZED) + return; + + DBG("ifname %s", def_ifname); + + snprintf(bpf_file, sizeof(bpf_file), BPF_FILE_PATH); + + rv = bpf_prog_load(bpf_file, BPF_PROG_TYPE_SOCKET_FILTER, + &bpf_info.obj, &bpf_info.prog_fd); + + if (rv) { + ERR("bpf_prog_load failed %d", rv); + return; + } + + bpf_info.map_fd = bpf_object__find_map_fd_by_name(bpf_info.obj, "countmap"); + + bpf_info.sock = open_raw_socket(def_ifname); + + if (setsockopt(bpf_info.sock, SOL_SOCKET, SO_ATTACH_BPF, &bpf_info.prog_fd, + sizeof(bpf_info.prog_fd)) != 0) { + close(bpf_info.sock); + ERR("setsockopt failed"); + return; + } + + memset(&bpf_map_info, 0, sizeof(bpf_map_info)); + bpf_info.timer = g_timeout_add_seconds(BPF_MAP_INTERVAL, check_bpf_map, NULL); + + g_state = ONLINE_MONITOR_STATE_MONITORING_STARTED; + notify_monitoring_state(ONLINE_MONITOR_STATE_MONITORING_STARTED, ONLINE_MONITOR_DETECTION_NONE); + + DBG("start_monitoring finished"); +} + +static void stop_monitoring(void) +{ + if (def_ifname[0] == 0) + return; + + if (g_state == ONLINE_MONITOR_STATE_MONITORING_STOPPED + || g_state == ONLINE_MONITOR_STATE_INITIALIZED + || g_state == ONLINE_MONITOR_STATE_UNINITIALIZED) + return; + + DBG("ifname %s", def_ifname); + + g_source_remove(bpf_info.timer); + bpf_info.timer = 0; + + close(bpf_info.sock); + + g_state = ONLINE_MONITOR_STATE_MONITORING_STOPPED; + notify_monitoring_state(ONLINE_MONITOR_STATE_MONITORING_STOPPED, ONLINE_MONITOR_DETECTION_NONE); +} + +static GKeyFile *load_keyfile(const char *pathname) +{ + GKeyFile *keyfile = NULL; + GError *error = NULL; + + keyfile = g_key_file_new(); + if (g_key_file_load_from_file(keyfile, pathname, 0, &error) != TRUE) { + DBG("Unable to open %s, error %s", pathname, error->message); + g_error_free(error); + + g_key_file_free(keyfile); + keyfile = NULL; + } + + DBG("loaded keyfile %s", pathname); + return keyfile; +} + +static int load_configuration(GKeyFile *keyfile) +{ + char **pos; + char **str_list; + gsize length; + + memset(&online_monitor_config, 0, sizeof(online_monitor_config)); + + online_monitor_config.is_enabled = g_key_file_get_boolean(keyfile, "General", "Enable", NULL); + + if (!online_monitor_config.is_enabled) + return -1; + + online_monitor_config.common_info = g_key_file_get_boolean(keyfile, "General", "CommonInfo", NULL); + online_monitor_config.dlog = g_key_file_get_boolean(keyfile, "General", "Dlog", NULL); + online_monitor_config.supplicant_log = g_key_file_get_boolean(keyfile, "General", "SuppLog", NULL); + online_monitor_config.packet_dump = g_key_file_get_boolean(keyfile, "General", "PacketDump", NULL); + online_monitor_config.max_report_count = g_key_file_get_integer(keyfile, "General", "MaxReportCount", NULL); + + if (!online_monitor_config.max_report_count) + return -1; + + str_list = g_key_file_get_string_list(keyfile, "General", "URLs", &length, NULL); + + if (!str_list) + return -1; + + if (length == 0) { + g_strfreev(str_list); + str_list = NULL; + return -1; + } + + pos = str_list; + + while (*pos) { + *pos = g_strstrip(*pos); + pos++; + } + + online_monitor_config.url_list = str_list; + + DBG("Enable %d, CommonInfo %d, Dlog %d, SuppLog %d, PacketDump %d, MaxReportCount %d", + online_monitor_config.is_enabled, + online_monitor_config.common_info, + online_monitor_config.dlog, + online_monitor_config.supplicant_log, + online_monitor_config.packet_dump, + online_monitor_config.max_report_count); + + while (*str_list) { + DBG("URL: %s", *str_list); + str_list++; + } + + return 0; +} + +static int init(void) +{ + GKeyFile *keyfile = NULL; + + INFO("Load online_monitor config file [%s]", ONLINE_MONITOR_CONF); + + keyfile = load_keyfile(ONLINE_MONITOR_CONF); + if (keyfile == NULL) { + ERR("Fail to load online_monitor config file"); + return -1; + } + + if (load_configuration(keyfile) != 0) { + ERR("load_configuration failed"); + return -1; + } + + g_key_file_free(keyfile); + + if (url_checker_init() != 0) { + ERR("url_checker_init failed"); + return -1; + } + + if (report_manager_init() != 0) { + url_checker_deinit(); + ERR("report_manager_init failed"); + return -1; + } + + DBG("online_monitor_plugin initialized"); + g_state = ONLINE_MONITOR_STATE_INITIALIZED; + + return 0; +} + +static int deinit(void) +{ + report_manager_deinit(); + url_checker_deinit(); + + if (online_monitor_config.url_list) + g_strfreev(online_monitor_config.url_list); + + g_slist_free(notifier_list); + notifier_list = NULL; + + DBG("online_monitor_plugin deinitialized"); + g_state = ONLINE_MONITOR_STATE_UNINITIALIZED; + + return 0; +} + +static int notify_online_state(char *ifname, gboolean state) +{ + if (g_state == ONLINE_MONITOR_STATE_UNINITIALIZED) { + ERR("Not initialized"); + return -1; + } + + if (ifname == NULL) { + ERR("Invalid parameter"); + return -1; + } + + DBG("notify_online_state ifname %s state %s", ifname, state ? "TRUE" : "FALSE"); + + if (state) { + if (g_strcmp0(def_ifname, ifname) != 0) { + stop_monitoring(); + g_strlcpy(def_ifname, ifname, sizeof(def_ifname)); + } + + if (g_state != ONLINE_MONITOR_STATE_MONITORING_STARTED) + start_monitoring(); + + } else { + if (g_strcmp0(def_ifname, ifname) == 0) { + stop_monitoring(); + def_ifname[0] = 0; + } + } + + return 0; +} + +extern struct netconfig_online_monitor_plugin_t netconfig_online_monitor_plugin + __attribute__ ((visibility("default"))); +struct netconfig_online_monitor_plugin_t netconfig_online_monitor_plugin = { + init, + deinit, + notify_online_state +}; diff --git a/plugin/online-monitor/online-monitor.h b/plugin/online-monitor/online-monitor.h new file mode 100644 index 0000000..312eae1 --- /dev/null +++ b/plugin/online-monitor/online-monitor.h @@ -0,0 +1,80 @@ +/* + * Network Configuration Module + * + * Copyright (c) 2021 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 "plugin.h" +#include "util.h" + +#ifdef USE_NETCONFIG_LOG +#include "log.h" +#else +#include + +#define NETCONFIG_TAG "NETCONFIG" +#define __LOG(level, format, arg...) \ + do { \ + SLOG(level, NETCONFIG_TAG, format, ## arg); \ + } while (0) + +#define DBG(format, arg...) __LOG(LOG_DEBUG, format, ## arg) +#define ERR(format, arg...) __LOG(LOG_ERROR, format, ## arg) +#endif + +#define ONLINE_MONITOR_CONF "/var/lib/net-config/online_monitor.conf" + +typedef enum { + ONLINE_MONITOR_STATE_UNINITIALIZED = 0, + ONLINE_MONITOR_STATE_INITIALIZED = 1, + ONLINE_MONITOR_STATE_MONITORING_STARTED = 2, + ONLINE_MONITOR_STATE_MONITORING_STOPPED = 3, + ONLINE_MONITOR_STATE_OFFLINE_DETECTED = 4, + ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED = 5, + ONLINE_MONITOR_STATE_URL_CHECK_FAILED = 6, +} online_monitor_state_e; + +typedef enum { + ONLINE_MONITOR_DETECTION_NONE = 0, + ONLINE_MONITOR_DETECTION_UNREACHABLE = 1, + ONLINE_MONITOR_DETECTION_DNS_REFUSED = 2, + ONLINE_MONITOR_DETECTION_NO_DNS_RESPONSE = 3, +} online_monitor_detection_e; + +typedef struct { + gboolean is_enabled; + gboolean common_info; + gboolean dlog; + gboolean supplicant_log; + gboolean packet_dump; + char **url_list; + int max_report_count; +} online_monitor_config_t; + +typedef void(*online_monitor_state_chaged_cb) + (online_monitor_state_e state, char *ifname, online_monitor_detection_e reason); + +void online_monitor_url_check_result(gboolean result); +void online_monitor_notifier_register(online_monitor_state_chaged_cb notifier); +void online_monitor_notifier_unregister(online_monitor_state_chaged_cb notifier); +online_monitor_config_t *online_monitor_get_configuration(void); + +int report_manager_init(void); +int report_manager_deinit(void); +int url_checker_init(void); +int url_checker_deinit(void); + + diff --git a/plugin/online-monitor/online_monitor.conf b/plugin/online-monitor/online_monitor.conf new file mode 100644 index 0000000..9dc8bbb --- /dev/null +++ b/plugin/online-monitor/online_monitor.conf @@ -0,0 +1,8 @@ +[General] +Enable=true +CommonInfo=true +Dlog=true +SuppLog=true +PacketDump=true +URLs=www.google.com;www.msn.com;www.yahoo.com;m.google.com;www.amazon.com;www.youtube.com +MaxReportCount=3 diff --git a/plugin/online-monitor/report-manager.c b/plugin/online-monitor/report-manager.c new file mode 100755 index 0000000..a825ebf --- /dev/null +++ b/plugin/online-monitor/report-manager.c @@ -0,0 +1,40 @@ +/* + * Network Configuration Module + * + * Copyright (c) 2021 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 "online-monitor.h" + +static void report_manager_state_chaged_cb(online_monitor_state_e state, + char *ifname, online_monitor_detection_e reason) +{ + DBG("state %d, ifname %s, reason %d", state, ifname, reason); +} + +int report_manager_init(void) +{ + online_monitor_notifier_register(report_manager_state_chaged_cb); + DBG("report_manager initialized"); + return 0; +} + +int report_manager_deinit(void) +{ + online_monitor_notifier_unregister(report_manager_state_chaged_cb); + DBG("report_manager deinitialized"); + return 0; +} diff --git a/plugin/online-monitor/url-checker.c b/plugin/online-monitor/url-checker.c new file mode 100755 index 0000000..a0029e8 --- /dev/null +++ b/plugin/online-monitor/url-checker.c @@ -0,0 +1,40 @@ +/* + * Network Configuration Module + * + * Copyright (c) 2021 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 "online-monitor.h" + +static void url_checker_state_chaged_cb(online_monitor_state_e state, + char* ifname, online_monitor_detection_e reason) +{ + DBG("state %d, ifname %s, reason %d", state, ifname, reason); +} + +int url_checker_init(void) +{ + online_monitor_notifier_register(url_checker_state_chaged_cb); + DBG("url_checker initialized"); + return 0; +} + +int url_checker_deinit(void) +{ + online_monitor_notifier_unregister(url_checker_state_chaged_cb); + DBG("url_checker deinitialized"); + return 0; +} diff --git a/src/network-state.c b/src/network-state.c index f807231..a137aff 100755 --- a/src/network-state.c +++ b/src/network-state.c @@ -112,6 +112,7 @@ struct netconfig_default_connection { char *essid; unsigned int freq; gboolean is_metered; + gboolean is_internet; }; static struct netconfig_default_connection @@ -380,6 +381,8 @@ static void __netconfig_clear_default_connection_info(void) if (netconfig_default_connection_info.profile != NULL) { + netconfig_notify_online_state(netconfig_default_connection_info.ifname, FALSE); + if (netconfig_is_wifi_profile(netconfig_default_connection_info.profile)) __netconfig_reset_ipv4_socket(netconfig_default_connection_info.ifname); @@ -406,6 +409,7 @@ static void __netconfig_clear_default_connection_info(void) netconfig_default_connection_info.freq = 0; netconfig_default_connection_info.is_metered = FALSE; + netconfig_default_connection_info.is_internet = FALSE; g_free(netconfig_default_connection_info.essid); netconfig_default_connection_info.essid = NULL; @@ -459,6 +463,15 @@ static gboolean __netconfig_get_default_connection_info(void) netconfig_default_connection_info.essid = g_strdup(value); } + } else if (g_strcmp0(key, "State") == 0) { + if (g_variant_is_of_type(var, G_VARIANT_TYPE_STRING)) { + value = g_variant_get_string(var, NULL); + + if (g_strcmp0(value, "online") == 0) { + netconfig_default_connection_info.is_internet = TRUE; + netconfig_notify_online_state(netconfig_default_connection_info.ifname, TRUE); + } + } } else if (g_strcmp0(key, "Ethernet") == 0) { g_variant_get(var, "a{sv}", &iter1); if (iter1 == NULL) @@ -1160,6 +1173,11 @@ gboolean netconfig_get_default_is_metered(void) return netconfig_default_connection_info.is_metered; } +gboolean netconfig_get_default_is_internet(void) +{ + return netconfig_default_connection_info.is_internet; +} + void netconfig_set_default_ipaddress(const char *ipaddr) { netconfig_default_connection_info.ipaddress = g_strdup(ipaddr); @@ -1175,6 +1193,12 @@ void netconfig_set_default_proxy(const char *proxy) netconfig_default_connection_info.proxy = g_strdup(proxy); } +void netconfig_set_default_is_internet(gboolean state) +{ + netconfig_default_connection_info.is_internet = state; + netconfig_notify_online_state(netconfig_default_connection_info.ifname, state); +} + void netconfig_update_default_profile(void) { if (__netconfig_get_default_connection_info()) diff --git a/src/signal-handler.c b/src/signal-handler.c index b627f7d..8e214a2 100755 --- a/src/signal-handler.c +++ b/src/signal-handler.c @@ -529,13 +529,18 @@ static void _service_signal_cb(GDBusConnection *conn, if (netconfig_is_wifi_profile(path) || netconfig_is_ethernet_profile(path)) { if (g_strcmp0(property, "ready") == 0) { + if (g_strcmp0(path, netconfig_get_default_profile()) == 0 + && netconfig_get_default_is_internet()) + netconfig_set_default_is_internet(FALSE); + for (idx = 0; idx < MAX_SOCKET_OPEN_RETRY; idx++) { sd = start_ip_conflict_mon(); if (sd != NULL) break; } } else if (g_strcmp0(property, "online") == 0) { - // do nothing + if (g_strcmp0(path, netconfig_get_default_profile()) == 0) + netconfig_set_default_is_internet(TRUE); } else { stop_ip_conflict_mon(); } diff --git a/src/utils/util.c b/src/utils/util.c index a6d44a5..1a18a4a 100755 --- a/src/utils/util.c +++ b/src/utils/util.c @@ -46,16 +46,25 @@ #include "wifi-state.h" #include "netdbus.h" -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" -#define MAC_INFO_FILEPATH tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info") -#define MAC_ADDRESS_FILEPATH "/sys/class/net/wlan0/address" -#define HEADED_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-headed.so" -#define TELEPHONY_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-telephony.so" -#define STC_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-stc.so" -#define BATTERY_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-battery.so" -#define CONNMAN_MAINFILE "/etc/connman/main.conf" -#define CONNMAN_WIFI_DEF_IFNAME "DefaultWifiInterface" +#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" +#define DBUS_INTERFACE_DBUS "org.freedesktop.DBus" +#define MAC_INFO_FILEPATH tzplatform_mkpath(TZ_SYS_ETC, "/.mac.info") +#define MAC_ADDRESS_FILEPATH "/sys/class/net/wlan0/address" +#if defined(TIZEN_ARCH_64) +#define HEADED_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-headed.so" +#define TELEPHONY_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-telephony.so" +#define STC_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-stc.so" +#define BATTERY_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-battery.so" +#define ONLINE_MONITOR_PLUGIN_FILEPATH "/usr/lib64/net-config-plugin-online-monitor.so" +#else +#define HEADED_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-headed.so" +#define TELEPHONY_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-telephony.so" +#define STC_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-stc.so" +#define BATTERY_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-battery.so" +#define ONLINE_MONITOR_PLUGIN_FILEPATH "/usr/lib/net-config-plugin-online-monitor.so" +#endif +#define CONNMAN_MAINFILE "/etc/connman/main.conf" +#define CONNMAN_WIFI_DEF_IFNAME "DefaultWifiInterface" static gboolean netconfig_device_picker_test = FALSE; typedef struct { @@ -67,14 +76,17 @@ static gboolean netconfig_plugin_headed_enabled = FALSE; static gboolean netconfig_plugin_telephony_enabled = FALSE; static gboolean netconfig_plugin_stc_enabled = FALSE; static gboolean netconfig_plugin_battery_enabled = FALSE; +static gboolean netconfig_plugin_online_monitor_enabled = FALSE; static void *handle_headed; static void *handle_telephony; static void *handle_stc; static void *handle_battery; +static void *handle_online_monitor; static struct netconfig_headed_plugin_t *headed_plugin; static struct netconfig_telephony_plugin_t *telephony_plugin; static struct netconfig_stc_plugin_t *stc_plugin; static struct netconfig_battery_plugin_t *battery_plugin; +static struct netconfig_online_monitor_plugin_t *online_monitor_plugin; static bool is_feature_checked[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, }; static bool feature_supported[NETCONFIG_SUPPORTED_FEATURE_MAX] = {0, }; @@ -1213,6 +1225,17 @@ void netconfig_battery_get_wifi_list(void *data) return battery_plugin->get_battery_wifi_list(data, __netconfig_stc_get_wifi_stats); } +void netconfig_notify_online_state(char *ifname, gboolean online_state) +{ + if (!netconfig_plugin_online_monitor_enabled) + return; + + if (!online_monitor_plugin) + return; + + online_monitor_plugin->notify_online_state(ifname, online_state); +} + void netconfig_set_vconf_int(const char * key, int value, gboolean log) { int ret = 0; @@ -1547,6 +1570,19 @@ void netconfig_plugin_init() } } + handle_online_monitor = dlopen(ONLINE_MONITOR_PLUGIN_FILEPATH, RTLD_NOW); + if (!handle_online_monitor) { + ERR("Can't load %s: %s", ONLINE_MONITOR_PLUGIN_FILEPATH, dlerror()); + } else { + online_monitor_plugin = dlsym(handle_online_monitor, "netconfig_online_monitor_plugin"); + if (!online_monitor_plugin) { + ERR("Can't load symbol: %s", dlerror()); + dlclose(handle_online_monitor); + } else { + if (online_monitor_plugin->init() == 0) + netconfig_plugin_online_monitor_enabled = TRUE; + } + } } void netconfig_plugin_deinit() @@ -1571,6 +1607,12 @@ void netconfig_plugin_deinit() dlclose(handle_battery); } + if (netconfig_plugin_online_monitor_enabled) { + netconfig_plugin_online_monitor_enabled = FALSE; + if (online_monitor_plugin) + online_monitor_plugin->deinit(); + dlclose(handle_online_monitor); + } } gboolean netconfig_get_headed_plugin_flag() -- 2.34.1