Add support for online monitoring report 53/263853/4
authorJaehyun Kim <jeik01.kim@samsung.com>
Sun, 12 Sep 2021 17:34:20 +0000 (02:34 +0900)
committerJaehyun Kim <jeik01.kim@samsung.com>
Wed, 15 Sep 2021 07:26:08 +0000 (07:26 +0000)
Change-Id: I957ee296b2835713bb5c59845f76393412ef5856
Signed-off-by: Jaehyun Kim <jeik01.kim@samsung.com>
packaging/net-config.spec
plugin/online-monitor/common_info_dump.sh [new file with mode: 0755]
plugin/online-monitor/report-manager.c
plugin/online-monitor/supp_log_dump.sh [new file with mode: 0755]

index 81c7123..c5fcbf8 100755 (executable)
@@ -198,6 +198,8 @@ mv %{_builddir}/%{name}-%{version}/net-config.wearable %{buildroot}%{_bindir}
 
 #online-monitor
 cp plugin/online-monitor/online_monitor.conf %{buildroot}/%{_localstatedir}/lib/net-config
+cp plugin/online-monitor/common_info_dump.sh %{buildroot}/opt/var/lib/net-config/
+cp plugin/online-monitor/supp_log_dump.sh %{buildroot}/opt/var/lib/net-config/
 
 %post
 chsmack -a 'System::Shared' %{_sysconfdir}/resolv.conf
@@ -290,3 +292,8 @@ mv /var/lib/net-config/settings-robot /var/lib/net-config/settings
 %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
+%attr(750,network_fw,network_fw) /opt/var/lib/net-config/common_info_dump.sh
+%attr(750,network_fw,network_fw) /opt/var/lib/net-config/supp_log_dump.sh
+
+%post plugin-online-monitor
+/usr/bin/mkdir -p /opt/usr/data/network/online_mon
diff --git a/plugin/online-monitor/common_info_dump.sh b/plugin/online-monitor/common_info_dump.sh
new file mode 100755 (executable)
index 0000000..611309c
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+#--------------------------------------
+#   Common Information Dump
+#--------------------------------------
+
+# not allow to use relative path
+if [[ $0 == "/"* ]]; then
+       echo "Absolute path"
+else
+       echo "Relative path"
+       exit -1
+fi
+
+export DISPLAY=:0.0
+
+REPORT_TYPE=offline_detection
+COMMON_INFO_FILE=$1
+
+echo $2 > ${COMMON_INFO_FILE}
+echo $3 >> ${COMMON_INFO_FILE}
+
+if [ $4 == ${REPORT_TYPE} ]; then
+echo "" >> ${COMMON_INFO_FILE}
+echo "[Default Connection Information]" >> ${COMMON_INFO_FILE}
+dbus-send --system --print-reply --dest=net.connman / net.connman.Manager.GetDefaultService >> ${COMMON_INFO_FILE}
+fi
+
+echo "" >> ${COMMON_INFO_FILE}
+echo [netstat -na] >> ${COMMON_INFO_FILE}
+/usr/bin/netstat -na >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [route -n] >> ${COMMON_INFO_FILE}
+/usr/sbin/route -n >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [route -A inet6 -n] >> ${COMMON_INFO_FILE}
+/usr/sbin/route -A inet6 -n >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [proc/net/wireless] >> ${COMMON_INFO_FILE}
+/usr/bin/cat /proc/net/wireless >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [resolv.conf] >> ${COMMON_INFO_FILE}
+/usr/bin/cat /etc/resolv.conf >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ifconfig -a] >> ${COMMON_INFO_FILE}
+/usr/sbin/ifconfig -a >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [iptables -L] >> ${COMMON_INFO_FILE}
+/usr/sbin/iptables -L >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ip6tables -L] >> ${COMMON_INFO_FILE}
+/usr/sbin/ip6tables -L >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [/proc/net/tcp] >> ${COMMON_INFO_FILE}
+/usr/bin/cat /proc/net/tcp >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [/proc/net/tcp6] >> ${COMMON_INFO_FILE}
+/usr/bin/cat /proc/net/tcp6 >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [/proc/net/route] >> ${COMMON_INFO_FILE}
+/usr/bin/cat /proc/net/route >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ip -4 rule] >> ${COMMON_INFO_FILE}
+/usr/sbin/ip -4 rule >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ip -6 rule] >> ${COMMON_INFO_FILE}
+/usr/sbin/ip -6 rule >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ip -4 route show table all] >> ${COMMON_INFO_FILE}
+/usr/sbin/ip -4 route show table all >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [ip -6 route show table all] >> ${COMMON_INFO_FILE}
+/usr/sbin/ip -6 route show table all >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [memory/dnet] >> ${COMMON_INFO_FILE}
+/usr/bin/vconftool -r get memory/dnet >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [memory/wifi] >> ${COMMON_INFO_FILE}
+/usr/bin/vconftool -r get memory/wifi >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [file/private/wifi] >> ${COMMON_INFO_FILE}
+/usr/bin/vconftool -r get file/private/wifi >> ${COMMON_INFO_FILE}
+echo "" >> ${COMMON_INFO_FILE}
+
+echo [db/wifi] >> ${COMMON_INFO_FILE}
+/usr/bin/vconftool -r get db/wifi >> ${COMMON_INFO_FILE}
index a825ebf..dd0a224 100755 (executable)
  *
  */
 
+#include <stdio.h>
+#include <sys/wait.h>
 #include "online-monitor.h"
 
+#define ONLINE_MON_LOG_PATH    "/opt/usr/data/network/online_mon/"
+
+#define OFFLINE_DETECT_COMMON_LOG    ONLINE_MON_LOG_PATH "offline_detection_common.log"
+#define OFFLINE_DETECT_DLOG          ONLINE_MON_LOG_PATH "offline_detection_dlog.log"
+#define OFFLINE_DETECT_PACKET_DUMP   ONLINE_MON_LOG_PATH "offline_detection_dump.log"
+#define OFFLINE_DETECT_PACKET_DUMP0  ONLINE_MON_LOG_PATH "offline_detection_dump.log0"
+#define OFFLINE_DETECT_PACKET_DUMP1  ONLINE_MON_LOG_PATH "offline_detection_dump.log1"
+
+#define DOWNGRADE_COMMON_LOG         ONLINE_MON_LOG_PATH "downgrade_common.log"
+#define DOWNGRADE_DLOG               ONLINE_MON_LOG_PATH "downgrade_dlog.log"
+#define DOWNGRADE_SUPP_LOG           ONLINE_MON_LOG_PATH "downgrade_supp.log"
+
+#define KILLALL_EXEC_PATH      "/usr/bin/killall"
+#define TCPDUMP_EXEC_PATH      "/usr/sbin/tcpdump"
+#define COMMON_INFO_SCRIPT     "/opt/var/lib/net-config/common_info_dump.sh"
+#define SUPPLICANT_LOG_SCRIPT  "/opt/var/lib/net-config/supp_log_dump.sh"
+#define DLOGUTIL_EXEC_PATH     "/usr/bin/dlogutil"
+
+static struct {
+       char *ifname;
+       online_monitor_state_e state;
+       online_monitor_detection_e reason;
+       gboolean tcpdump_started;
+       int detection_count;
+       int downgrade_count;
+       int max_log_count;
+} report_manager_info;
+
+static inline void report_manager_update_file_revision(int rev, const char *file_path)
+{
+       int next_log_rev = 0;
+       char *log_file = NULL;
+       char *next_log_file = NULL;
+
+       next_log_rev = rev + 1;
+
+       log_file = g_strdup_printf("%s.%d", file_path, rev);
+       next_log_file = g_strdup_printf("%s.%d", file_path, next_log_rev);
+
+       if (next_log_rev >= report_manager_info.max_log_count - 1)
+               remove(next_log_file);
+
+       if (access(next_log_file, F_OK) == 0)
+               report_manager_update_file_revision(next_log_rev, file_path);
+
+       if (rename(log_file, next_log_file) != 0)
+               remove(log_file);
+
+       g_free(log_file);
+       g_free(next_log_file);
+}
+
+static inline void report_manager_make_backup(const char *file_path)
+{
+       const int rev = 0;
+       char *backup = NULL;
+
+       backup = g_strdup_printf("%s.%d", file_path, rev);
+
+       if (access(backup, F_OK) == 0)
+               report_manager_update_file_revision(rev, file_path);
+
+       if (rename(file_path, backup) != 0)
+               remove(file_path);
+
+       g_free(backup);
+}
+
+static int report_manager_execute_file(const char *file_path,
+               char *const args[], char *const envs[])
+{
+       pid_t pid = 0;
+       int status = 0;
+       int rv = 0;
+       errno = 0;
+       register unsigned int index = 0;
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+       while (args[index] != NULL) {
+               DBG("%s", args[index]);
+               index++;
+       }
+
+       if (!(pid = fork())) {
+               DBG("pid(%d), ppid (%d)", getpid(), getppid());
+               DBG("Inside child, exec (%s) command", file_path);
+
+               errno = 0;
+               if (execve(file_path, args, envs) == -1) {
+                       DBG("Fail to execute command (%s)",
+                                       strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+                       exit(1);
+               }
+       } else if (pid > 0) {
+               if (waitpid(pid, &status, 0) == -1)
+                       DBG("wait pid (%u) status (%d)", pid, status);
+
+               if (WIFEXITED(status)) {
+                       rv = WEXITSTATUS(status);
+                       DBG("exited, status=%d", rv);
+               } else if (WIFSIGNALED(status)) {
+                       DBG("killed by signal %d", WTERMSIG(status));
+               } else if (WIFSTOPPED(status)) {
+                       DBG("stopped by signal %d", WSTOPSIG(status));
+               } else if (WIFCONTINUED(status)) {
+                       DBG("continued");
+               }
+
+               return rv;
+       }
+
+       DBG("failed to fork(%s)",
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+       return -EIO;
+}
+
+static void no_wait_signal_handler()
+{
+       pid_t child_pid = 0;
+       int state = 0;
+
+       child_pid = waitpid(-1, &state, WNOHANG);
+
+       DBG("child_id(%d) state(%d)", child_pid, WEXITSTATUS(state));
+}
+
+static int report_manager_execute_file_no_wait(const char *file_path, char *const args[])
+{
+       pid_t pid = 0;
+       int rv = 0;
+       errno = 0;
+       register unsigned int index = 0;
+
+       struct sigaction act;
+       int state = 0;
+       char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
+
+       act.sa_handler = no_wait_signal_handler;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = 0;
+
+       state = sigaction(SIGCHLD, &act, 0);
+       if (state != 0) {
+               DBG("sigaction() : %d", state);
+               return -1;
+       }
+
+       while (args[index] != NULL) {
+               DBG("%s", args[index]);
+               index++;
+       }
+
+       if (!(pid = fork())) {
+               DBG("pid(%d), ppid (%d)", getpid(), getppid());
+               DBG("Inside child, exec (%s) command", file_path);
+
+               errno = 0;
+               if (execvp(file_path, args) == -1) {
+                       ERR("Fail to execute command (%s)",
+                               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+                       return -1;
+               }
+       } else if (pid > 0) {
+               ERR("Successfully launched child process");
+               return rv;
+       }
+
+       DBG("failed to fork(%s)",
+               strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER));
+       return -EIO;
+}
+
+static gboolean report_manager_stop_tcpdump(void)
+{
+       int ret;
+       const char *path = KILLALL_EXEC_PATH;
+       char *const args[] = { KILLALL_EXEC_PATH, "tcpdump", NULL };
+       char *const envs[] = { NULL };
+
+       if (!report_manager_info.tcpdump_started) {
+               DBG("tcpdump is not running");
+               return FALSE;
+       }
+
+       ret = report_manager_execute_file(path, args, envs);
+       if (ret < 0) {
+               DBG("Failed to Kill tcpdump, ret : %d\n", ret);
+               return FALSE;
+       }
+
+       report_manager_info.tcpdump_started = FALSE;
+
+       return TRUE;
+}
+
+static gboolean report_manager_start_tcpdump(void)
+{
+       int ret;
+       const char *start_path = TCPDUMP_EXEC_PATH;
+
+       if (access(OFFLINE_DETECT_PACKET_DUMP0, F_OK) == 0)
+               report_manager_make_backup(OFFLINE_DETECT_PACKET_DUMP0);
+       if (access(OFFLINE_DETECT_PACKET_DUMP1, F_OK) == 0)
+               report_manager_make_backup(OFFLINE_DETECT_PACKET_DUMP1);
+
+       char *const start_args[] = { TCPDUMP_EXEC_PATH,
+                       "-W", "2", "-C", "25", "-i", report_manager_info.ifname,
+                       "-s", "0", "-w", OFFLINE_DETECT_PACKET_DUMP, NULL};
+
+       if (report_manager_info.tcpdump_started) {
+               DBG("kill tcpdump.");
+               gboolean ret = report_manager_stop_tcpdump();
+
+               if (!ret)
+                       DBG("Failed to kill tcpdump.. ret : %d", ret);
+
+               return FALSE;
+       }
+
+       ret = report_manager_execute_file_no_wait(start_path, start_args);
+       if (ret < 0) {
+               DBG("Failed to start tcpdump, ret : %d", ret);
+               return FALSE;
+       }
+
+       report_manager_info.tcpdump_started = TRUE;
+
+       return report_manager_info.tcpdump_started;
+}
+
+static char *convert_detection_reason(online_monitor_detection_e reason)
+{
+       switch (reason) {
+       case ONLINE_MONITOR_DETECTION_UNREACHABLE:
+               return "Destination Unreachable";
+       case ONLINE_MONITOR_DETECTION_DNS_REFUSED:
+               return "DNS Refused";
+       case ONLINE_MONITOR_DETECTION_NO_DNS_RESPONSE:
+               return "No DNS Response";
+       default:
+               return "None";
+       }
+}
+
+static void report_manager_start_common_info_dump(gboolean is_downgrade)
+{
+       int rv = 0;
+       gchar *path = COMMON_INFO_SCRIPT;
+       char log_file_name[100] = { 0, };
+       char detection_count[64] = { 0, };
+       char sub_info[64] = { 0, };
+       char report_type[32] = { 0, };
+
+       if (is_downgrade) {
+               g_snprintf(log_file_name, 100, DOWNGRADE_COMMON_LOG);
+               g_snprintf(detection_count, 64, "Offline Detection Count: %d",
+                               report_manager_info.detection_count);
+               g_snprintf(sub_info, 64, "Downgrade Count: %d",
+                               report_manager_info.downgrade_count);
+               g_snprintf(report_type, 32, "downgrade");
+       } else {
+               g_snprintf(log_file_name, 100, OFFLINE_DETECT_COMMON_LOG);
+               g_snprintf(detection_count, 64, "Offline Detection Count: %d",
+                               report_manager_info.detection_count);
+               g_snprintf(sub_info, 64, "Detection Reason: %s",
+                               convert_detection_reason(report_manager_info.reason));
+               g_snprintf(report_type, 32, "offline_detection");
+       }
+
+       if (access(log_file_name, F_OK) == 0)
+                       report_manager_make_backup(log_file_name);
+
+       char *const args[] = { COMMON_INFO_SCRIPT,
+                       log_file_name, detection_count, sub_info, report_type, NULL };
+       char *const envs[] = { NULL };
+
+       rv = report_manager_execute_file(path, args, envs);
+
+       if (rv < 0)
+               ERR("Fail to execute network log dump shell");
+}
+
+static void report_manager_start_dlog_dump(gboolean is_downgrade)
+{
+       int rv = 0;
+       gchar *path = DLOGUTIL_EXEC_PATH;
+       char log_file_name[100] = { 0, };
+
+       if (is_downgrade)
+               g_snprintf(log_file_name, 100, DOWNGRADE_DLOG);
+       else
+               g_snprintf(log_file_name, 100, OFFLINE_DETECT_DLOG);
+
+       if (access(log_file_name, F_OK) == 0)
+                       report_manager_make_backup(log_file_name);
+
+       char *const args[] = { DLOGUTIL_EXEC_PATH, "-f", log_file_name, "-d", "-t", "2000", NULL };
+       char *const envs[] = { NULL };
+
+       rv = report_manager_execute_file(path, args, envs);
+
+       if (rv < 0)
+               ERR("Fail to execute dlog dump command");
+}
+
+static void report_manager_start_supp_dump(void)
+{
+       int rv = 0;
+       gchar *path = SUPPLICANT_LOG_SCRIPT;
+
+       if (access(DOWNGRADE_SUPP_LOG, F_OK) == 0)
+                       report_manager_make_backup(DOWNGRADE_SUPP_LOG);
+
+       char *const args[] = { SUPPLICANT_LOG_SCRIPT, DOWNGRADE_SUPP_LOG, NULL };
+       char *const envs[] = { NULL };
+
+       rv = report_manager_execute_file(path, args, envs);
+
+       if (rv < 0)
+               ERR("Fail to execute supplicant log dump shell");
+}
+
+static void report_manager_start_downgrade_dump(void)
+{
+       online_monitor_config_t *config = online_monitor_get_configuration();
+
+       report_manager_stop_tcpdump();
+
+       if (config->common_info)
+               report_manager_start_common_info_dump(TRUE);
+
+       if (config->dlog)
+               report_manager_start_dlog_dump(TRUE);
+
+       if (config->supplicant_log)
+               report_manager_start_supp_dump();
+}
+
+static void report_manager_start_detection_dump(void)
+{
+       online_monitor_config_t *config = online_monitor_get_configuration();
+
+       if (config->common_info)
+               report_manager_start_common_info_dump(FALSE);
+
+       if (config->dlog)
+               report_manager_start_dlog_dump(FALSE);
+
+       if (config->packet_dump)
+               report_manager_start_tcpdump();
+}
+
 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);
+
+       report_manager_info.state = state;
+       report_manager_info.reason = reason;
+
+       switch (state) {
+       case ONLINE_MONITOR_STATE_MONITORING_STARTED:
+               report_manager_info.ifname = ifname;
+               break;
+       case ONLINE_MONITOR_STATE_MONITORING_STOPPED:
+               report_manager_stop_tcpdump();
+               report_manager_info.ifname = NULL;
+               break;
+       case ONLINE_MONITOR_STATE_OFFLINE_DETECTED:
+               report_manager_info.detection_count++;
+               report_manager_start_detection_dump();
+               break;
+       case ONLINE_MONITOR_STATE_URL_CHECK_SUCCEEDED:
+               report_manager_stop_tcpdump();
+               break;
+       case ONLINE_MONITOR_STATE_URL_CHECK_FAILED:
+               report_manager_info.downgrade_count++;
+               report_manager_start_downgrade_dump();
+               break;
+       default :
+               break;
+       }
 }
 
 int report_manager_init(void)
 {
-       online_monitor_notifier_register(report_manager_state_chaged_cb);
+       online_monitor_config_t *config = online_monitor_get_configuration();
+
+       if (config->common_info || config->dlog || config->supplicant_log || config->packet_dump)
+               online_monitor_notifier_register(report_manager_state_chaged_cb);
+
+       memset(&report_manager_info, 0, sizeof(report_manager_info));
+
+       report_manager_info.max_log_count = config->max_report_count;
+       report_manager_info.state = ONLINE_MONITOR_STATE_INITIALIZED;
        DBG("report_manager initialized");
+
        return 0;
 }
 
 int report_manager_deinit(void)
 {
        online_monitor_notifier_unregister(report_manager_state_chaged_cb);
+       report_manager_stop_tcpdump();
+
+       report_manager_info.state = ONLINE_MONITOR_STATE_UNINITIALIZED;
        DBG("report_manager deinitialized");
+
        return 0;
 }
diff --git a/plugin/online-monitor/supp_log_dump.sh b/plugin/online-monitor/supp_log_dump.sh
new file mode 100755 (executable)
index 0000000..745f55e
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/sh
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+#--------------------------------------
+#   Supplicant Log Dump
+#--------------------------------------
+
+# not allow to use relative path
+if [[ $0 == "/"* ]]; then
+       echo "Absolute path"
+else
+       echo "Relative path"
+       exit -1
+fi
+
+export DISPLAY=:0.0
+
+SUPP_LOG_FILE=$1
+SUPP_LOG_SIZE=$(stat -c %s "/opt/usr/data/network/wpa_supplicant.log")
+
+if [[ SUPP_LOG_SIZE -lt 200000 ]]; then
+if [[ -f "/opt/usr/data/network/wpa_supplicant.log.0" ]]; then
+    cp /opt/usr/data/network/wpa_supplicant.log.0 ${SUPP_LOG_FILE}
+fi
+fi
+
+cat /opt/usr/data/network/wpa_supplicant.log >> ${SUPP_LOG_FILE}