#!/usr/bin/env bash

# Copyright (c) 2021 Broadcom. All Rights Reserved.
# The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
#
# THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE SECRETS OF
# BROADCOM. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
# EXPRESS WRITTEN PERMISSION OF BROADCOM.
#
# The Licensed Software and Documentation are deemed to be commercial computer
# software as defined in FAR 12.212 and subject to restricted rights as
# defined in FAR Section 52.227-19 "Commercial Computer Software - Restricted
# Rights" and DFARS 227.7202, Rights in "Commercial Computer Software or
# Commercial Computer Software Documentation," as applicable, and any successor
# regulations, whether delivered by Broadcom as on premises or hosted services.
# Any use, modification, reproduction release, performance, display or
# disclosure of the Licensed Software and Documentation by the U.S. Government
# shall be solely in accordance with the terms of this Agreement.

# Symantec Integrated Cyber Defense Exchange
# Support Information Gathering Tool

#force environment variables to be loaded
source /etc/environment

if [ -z ${SYMC_HOME+x} ]; then
    echo "ICDx is not installed. Quitting. (SYMC_HOME environment variable is not set.)"
    exit 1
fi

# Linux Distro
UBUNTU="Ubuntu"
REDHAT="Red Hat Enterprise Linux Server"
CENTOS="CentOS Linux"
DISTRO=$(cat /etc/os-release | grep -E "\bNAME=" | cut -d= -f 2 | tr -d '"')

# current working directory (where the script was launched)
dir=${PWD}

# Setting all flags to false by default
machine_flag=false
network_flag=false
icdx_flag=false
no_logs_flag=false
no_zip_flag=false
# Checks that information has been requested
is_input_valid=false

function usage() {
cat <<EOF
Symantec Integrated Cyber Defense Exchange, version 1.4.2
Support Information Gathering Tool
Copyright (c) 2021 Broadcom. All Rights Reserved.
The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
-----HELP MENU-----
-a or --all:
    Gathers all information
-m or --machine:
    Gathers all machine information
-n or --network:
    Gathers all network information
-i or --icdx:
    Gathers all ICDx information
-l or --nologs:
    Omits log files
-z or --nozip
    Does not create a .zip file upon completion
-h or --help
    Prints helpful information on how to use this tool
EOF
}

if [[ $EUID -ne 0 ]]; then
    echo "You must run this script as root or sudo."
    exit 1
fi

#Checking for specified settings
#No arguments given
if [ $# == 0 ]; then
    #Displays error along with help message
    echo "Too few arguments, at least one flag is required."
    usage
    exit 1
fi
#Loop going through all the arguments given
for var in "$@"
do
    check=$var
    #Help option
    if [  "$check" == "-h" ] || [ "$check" == "--help" ]; then
        usage
        exit
    #All information option
    elif [ "$check" == "-a" ] || [ "$check" == "--all" ]; then
        echo "All information requested"
        machine_flag=true
        network_flag=true
        icdx_flag=true
        is_input_valid=true
    #Machine information option
    elif [ "$check" == "-m" ] || [ "$check" == "--machine" ]; then
        if [ $machine_flag == "false" ]; then
            echo "Machine information requested"
        fi
        machine_flag=true
        is_input_valid=true
    #Network information option
    elif [ "$check" == "-n" ] || [ "$check" == "--network" ]; then
        if [ $network_flag == "false" ]; then
            echo "Network information requested"
        fi
        network_flag=true
        is_input_valid=true
    #ICDx information option
    elif [ "$check" == "-i" ] || [ "$check" == "--icdx" ]; then
        if [ $icdx_flag == "false" ]; then
            echo "ICDx information requested"
        fi
        icdx_flag=true
        is_input_valid=true
    #No Log option
    elif [ "$check" == "-l" ] || [ "$check" == "--nologs" ]; then
        if [ $is_input_valid == "false" ]; then
            echo "Please specify what information you want to gather without log files."
            echo "Try 'icdx-info --help' for list of available options."
            exit 1
        fi
        if [ $no_logs_flag == "false" ]; then
            echo "Omitting logs"
        fi
        no_logs_flag=true
    #No Zip option
    elif [ "$check" == "-z" ] || [ "$check" == "--nozip" ]; then
        if [ $is_input_valid == "false" ]; then
            echo "Please specify what information you want to gather without zipping files."
            echo "Try 'icdx-info --help' for list of available options."
            exit 1
        fi
        if [ $no_zip_flag == "false" ]; then
            echo "Files will not be zipped"
        fi
        no_zip_flag=true
    else
        echo "icdx-info: invalid option -- '${var}' Try 'icdx-info --help' for more information."
        exit 1
    fi
done

# Echo then run a command
function run() {
    args=()
    for arg in "$@"; do
        args+=("${arg}")
    done

    printf "** *** ***** ******* *********** *************\n"
    printf "%q " "${args[@]}"
    printf "\n\n"
    "${args[@]}"
    printf "\n"
}

#Creating the directory to save information
curr_date=$(date +"%Y-%m-%d %T")
file_date="${curr_date//:/_}"
file_date="${file_date//-/_}"
file_date="${file_date// /_}"
output_dir_name="icdx-info_${file_date}"
output_path=${dir}/${output_dir_name}

echo "Creating output directory: ${output_dir_name}"
mkdir "${output_path}"

#####Machine Information#####
if [ $machine_flag == "true" ]; then
    echo "Gathering Machine Information"

    mkdir "${output_path}"/machine_info
    pushd "${output_path}"/machine_info > /dev/null

    cat > README.txt <<EOF
File/Directory       Description
--------------       ---------------------------------------------------------
date_time.txt        Date time information.
env_vars.txt         Enviromment variables retrieved with the env command.
linux_users.txt      Users on the machine.
list_cpu.txt         The specifications for the CPU.
list_hardware.html   The hardware specifications in HTML.
mem_info.txt         Information about the memory on the machine.
modules.txt          Module information.
os_release.txt       OS release information.
packages.txt         All the packages installed on the machine.
partition_info.txt   Information about the partitions on the machine.
processes.txt        Process information.
uname_info.txt       System information retrieved with the uname command.
EOF

    run date > date_time.txt 2>&1
    run timedatectl >> date_time.txt 2>&1

    run env > env_vars.txt 2>&1

    run lscpu > list_cpu.txt 2>&1

    lshw -html -sanitize > list_hardware.html 2>&1

    run cat /etc/passwd > linux_users.txt 2>&1

    run free > mem_info.txt 2>&1
    run cat /proc/meminfo >> mem_info.txt 2>&1
    run cat /proc/mounts >> mem_info.txt 2>&1

    run lsmod > modules.txt 2>&1
    run lspci >> modules.txt 2>&1

    run cat /etc/os-release > os_release.txt 2>&1

    run df -h > partition_info.txt 2>&1
    run fdisk -l >> partition_info.txt 2>&1

    if [ "${DISTRO}" = "${REDHAT}" ] || [ "${DISTRO}" = "${CENTOS}" ]; then
        run yum list > packages.txt 2>/dev/null
    else
        run apt list > packages.txt 2>/dev/null
    fi

    run ps fauxx > processes.txt 2>&1
    run lsof -b -M -n -l >> processes.txt 2>/dev/null

    username=$(whoami)
    minfo=$(uname -m)
    ninfo=$(uname -n)
    pinfo=$(uname -p)
    rinfo=$(uname -r)
    sinfo=$(uname -s)
    vinfo=$(uname -v)
    iinfo=$(uname -i)
    oinfo=$(uname -o)
    {
        echo "User: ${username}"
        echo "Machine Type: ${minfo}"
        echo "Node Hostname: ${ninfo}"
        echo "Processor Type: ${pinfo}"
        echo "Kernel Release: ${rinfo}"
        echo "Kernel Name: ${sinfo}"
        echo "Kernel Version: ${vinfo}"
        echo "Hardware Platform: ${iinfo}"
        echo "Operating System: ${oinfo}"
    } > uname_info.txt

    popd > /dev/null
fi

#####Network Information#####
if [ $network_flag == "true" ]; then
    echo "Gathering Network Information"

    mkdir "${output_path}"/network_info
    pushd "${output_path}"/network_info > /dev/null

    cat > README.txt <<EOF
File/Directory           Description
----------------------   -----------------------------------------------------
firewall_rules.txt       List of Firewall added user rules.
firewall_status.txt      Status of the Firewall verbose status.
hostname.txt             The hostname of the machine.
hosts.txt                The hosts of the machine.
network_interfaces.txt   List of the network interfaces.
ip_cmds.txt              The common ip command outputs.
EOF
# trace.txt                Route from the machine to support.symantec.com.

    #Gathering network information
    if [ "${DISTRO}" = "${REDHAT}" ] || [ "${DISTRO}" = "${CENTOS}" ]; then
        cat >> README.txt <<EOF
sysconfig_network.txt    The /etc/sysconfig/network file.
ifcfg/                   Interface files in /etc/sysconfig/network-scripts.
EOF
        run cat /etc/sysconfig/network > sysconfig_network.txt 2>&1
        mkdir ifcfg/
        cp -r /etc/sysconfig/network-scripts/ifcfg-* ifcfg/
    elif [ "${DISTRO}" = "${UBUNTU}" ]; then
        cat >> README.txt <<EOF
ifconfig.txt             The status of the currently active interfaces.
network_interfaces.txt   The /etc/network/interfaces file.
netplan/                 Files in /etc/netplan.
EOF
        run ifconfig -a > ifconfig.txt 2>&1
        run cat /etc/network/interfaces > network_interfaces.txt 2>&1

        # netplan is not always installed; installed by default in Ubuntu 18
        if [ -d /etc/netplan ]; then
            mkdir netplan
            cp -r /etc/netplan/* netplan
        fi
    fi

    run cat /etc/hosts > hosts.txt 2>&1

    run cat /etc/hostname > hostname.txt 2>&1

    if [ "${DISTRO}" = "${REDHAT}" ] || [ "${DISTRO}" = "${CENTOS}" ]; then
        if command -v firewall-cmd > /dev/null 2>&1 ; then
            run firewall-cmd --state > firewall_status.txt 2>&1
            run firewall-cmd --list-all-zones >> firewall_status.txt 2>&1
            run firewall-cmd --list-all > firewall_rules.txt 2>&1
        else
            echo "firewall-cmd: not installed" > firewall_status.txt
        fi
    elif [ "${DISTRO}" = "${UBUNTU}" ]; then
        if command -v ufw > /dev/null 2>&1 ; then
            run ufw status verbose > firewall_status.txt 2>&1
            run ufw show added > firewall_rules.txt 2>&1
        else
            echo "ufw: not installed" > firewall_status.txt
        fi
    fi

    # if command -v traceroute > /dev/null 2>&1 ; then
    #     run traceroute support.symantec.com > trace.txt 2>&1
    # else
    #     run tracepath support.symantec.com > trace.txt 2>&1
    # fi

    {
        run ip addr show
        run ip link show
        run ip route show
        run netstat -neopa
        run iptables -vnL
        run ip6tables -vnL
    } > ip_cmds.txt 2>&1

    popd > /dev/null
fi

function gather_installation() {
    installer_directory=${1}
    installer_base_dest=${2}
    no_logs_flag=${3}

    installer_basename=$(basename "${installer_directory}")
    installer_dest=${installer_base_dest}/${installer_basename}
    if [ -e "${installer_dest}" ] ; then
        counter=1
        while [ -e "${installer_dest}"_"${counter}" ] ; do
            counter=$((counter+1))
        done
        installer_dest=${installer_dest}_${counter}
    fi

    mkdir -p "${installer_dest}"

    cp "${installer_directory}"/*.yaml "${installer_dest}"

    # remove plaintext passwords in yaml files
    sed -i -r 's/(.*password):(.*)/\1: # password removed by icdx-info script/' "${installer_dest}"/*.yaml

    run find "${installer_directory}" > "${installer_dest}/installer_tree.txt" 2>&1

    if [ "$no_logs_flag" == "false" ]; then
        cp "${installer_directory}"/*.log "${installer_dest}"
    fi
}

#####ICDx Information#####
if [ $icdx_flag == "true" ]; then
    echo "Gathering ICDx Information"

    mkdir "${output_path}"/icdx_info
    pushd "${output_path}"/icdx_info > /dev/null

    icdx_gather_path=${PWD}

    cat > README.txt <<EOF
File/Directory          Description
-------------------     ------------------------------------------------------
fs/                     Directory with files from machine filesystem:
                          * ICDx configuration and version files ($SYMC_HOME
                            excluding binaries)
                          * Log files, if enabled ($SYMC_LOG and /var/log).
                          * Linux package manager configuration (/etc).
                          * Nginx configuration (/etc/nginx).
                          * RabbitMQ configuration (/etc/rabbitmq).
home_tree.txt           File structure of the ICDx Application location.
data_tree.txt           File structure of the ICDx Data and Archives location.
data_usage.txt          Disk space usage of ICDx Data and Archive location.
java_info.txt           Java location and version.
rabbitmq_info.txt       RabbitMQ information.
status/                 Directory with statuses of the core ICDx services.
systemctl_status.txt    Statuses of the systemctl launched ICDx services.
installer_files/        Directory with configuration, log files (if enabled),
                        and file structures of ICDx installers on machine.
EOF

    filesystem_dest=${icdx_gather_path}/fs

    symc_home_dest=${filesystem_dest}${SYMC_HOME}
    mkdir -p "${symc_home_dest}"
    cp -rP "${SYMC_HOME}"/apps "${symc_home_dest}"
    cp -rP "${SYMC_HOME}"/repo "${symc_home_dest}"
    cp -rP "${SYMC_HOME}"/etc "${symc_home_dest}"
    mkdir "${symc_home_dest}"/portal_dx
    cp "${SYMC_HOME}"/portal_dx/icdx.json "${symc_home_dest}"/portal_dx

    # remove plaintext passwords in kafka properties files
    # For details of this file iteration technique see: https://github.com/koalaman/shellcheck/wiki/SC2044
    shopt -s globstar nullglob
    for file in "${symc_home_dest}"/apps/**/kafka*.properties
    do
        sed -i -r 's/(.*password)( *)=(.*)/\1\2= # password removed by icdx-info script/' "$file"
    done

    etc_dest=${filesystem_dest}/etc
    mkdir -p "${etc_dest}"/nginx
    cp -rP /etc/nginx/conf.d "${etc_dest}"/nginx
    cp -rP /etc/rabbitmq "${etc_dest}"

    if [ "${DISTRO}" = "${REDHAT}" ] || [ "${DISTRO}" = "${CENTOS}" ]; then
        cp /etc/yum.conf "${etc_dest}"
        cp -rP /etc/yum.repos.d "${etc_dest}"
    elif [ "${DISTRO}" = "${UBUNTU}" ]; then
        mkdir -p "${etc_dest}/apt"
        if [ -f "/etc/apt/apt.conf" ]; then
            cp /etc/apt/apt.conf "${etc_dest}"/apt
        fi
        if [ -f "/etc/apt/apt.conf.d/proxy.conf" ]; then
            mkdir -p "${etc_dest}"/apt/apt.conf.d
            cp /etc/apt/apt.conf.d/proxy.conf "${etc_dest}"/apt/apt.conf.d
        fi
        cp /etc/apt/sources.list "${etc_dest}"/apt
        cp -r /etc/apt/sources.list.d "${etc_dest}"/apt
    fi

    if [ "$no_logs_flag" == "false" ]; then
        if [[ "${SYMC_LOG}" = /* ]]; then  # check if SYMC_LOG is an absolute path
            # Only recurively copy all of SYMC_LOG if it is an absolute path
            # A recursive copy fails with a relative path like ./log
            # echo "Gathering log files: ${SYMC_LOG}"
            symc_log_dest=${filesystem_dest}${SYMC_LOG}
            mkdir -p "${symc_log_dest}"
            cp -rP "${SYMC_LOG}"/* "${symc_log_dest}"
        else
            # Relative log path. Look for ICDx apps and build actual log path for each.
            # Apps have the pattern directory name patternr: <name>-<major>.<minor>.<patch>-<build>
            # For details of this file iteration technique see: https://github.com/koalaman/shellcheck/wiki/SC2044
            while IFS= read -r -d '' path
            do
                absolute_log_path=$(realpath "$path"/"${SYMC_LOG}")
                if [ -d "${absolute_log_path}" ]; then  # if log directory actual exists
                    # echo "Gathering log files: ${absolute_log_path}"
                    symc_log_dest=${filesystem_dest}${absolute_log_path}
                    mkdir -p "${symc_log_dest}"
                    cp -rP "${absolute_log_path}"/* "${symc_log_dest}"
                fi
            done <  <(find "${SYMC_HOME}" -type d -name "*-*.*.*-*" -print0)
        fi
        var_log_dest=${filesystem_dest}/var/log
        mkdir -p "${var_log_dest}"
        cp -rP /var/log/nginx "${var_log_dest}"
        cp -rP /var/log/rabbitmq "${var_log_dest}"
    fi

    run find "$SYMC_HOME" -printf "%M %u %g %p\n" > home_tree.txt 2>&1
    run find "$SYMC_DATA" -printf "%M %u %g %p\n" > data_tree.txt 2>&1

	  run ls -al "${SYMC_LOG}"/.. > symc_log_tree.txt 2>&1

    run du -h "$SYMC_DATA" > data_usage.txt 2>&1

    run which java > java_info.txt 2>&1
    run java -version >> java_info.txt 2>&1

	  run cat /etc/group > etc_group.txt 2>&1

    {
        run rabbitmqctl list_users
        run rabbitmqctl list_vhosts
        run rabbitmqctl cluster_status
        run rabbitmqctl list_connections
    }  > rabbitmq_info.txt 2>&1

    all_vhosts=$(rabbitmqctl list_vhosts -q | xargs -n1 | sort -u)

    echo "** *** ***** ******* *********** *************" >> rabbitmq_info.txt
    echo "** *** ***** ******* *********** *************" >> rabbitmq_info.txt
    printf "Exchange information for each vhost\n\n" >> rabbitmq_info.txt
    for vhost in $all_vhosts; do
        run rabbitmqctl list_exchanges -p $vhost >> rabbitmq_info.txt 2>&1
    done

    echo "** *** ***** ******* *********** *************" >> rabbitmq_info.txt
    echo "** *** ***** ******* *********** *************" >> rabbitmq_info.txt
    printf "Queue information for each vhost\n\n" >> rabbitmq_info.txt
    for vhost in $all_vhosts; do
        run rabbitmqctl list_queues -p $vhost >> rabbitmq_info.txt 2>&1
    done

    mkdir status
    run curl -sk https://localhost/api/dx/archives/status > status/archives.txt 2>&1
    run curl -sk https://localhost/api/dx/launcher/status > status/launcher.txt 2>&1
    run curl -sk https://localhost/api/dx/logger/status > status/logger.txt 2>&1
    run curl -sk https://localhost/api/dx/repo/status > status/repo.txt 2>&1
    run curl -sk https://localhost/api/dx/stats/status > status/stats.txt 2>&1

    {
        run systemctl list-units --state=running
        run systemctl status launcher_dx.service
        run systemctl status logback_dx.service
        run systemctl status nginx.service
        run systemctl status rabbitmq-server.service
        run systemctl list-units -a
    } > systemctl_status.txt 2>&1

    echo "Scanning for ICDx installers"
    installer_files=${icdx_gather_path}/installer_files
    mkdir -p "${installer_files}"
    # For details of this file iteration technique see: https://github.com/koalaman/shellcheck/wiki/SC2044
    while IFS= read -r -d '' path
    do
        echo "Gathering ICDx installer: $path"
        gather_installation "$path" "${installer_files}" "$no_logs_flag"
    done <  <(find / -type d -name "icdx-installer-*" -print0)

    popd > /dev/null
fi

cd "${dir}"

# Zips files if requested
if [ $no_zip_flag == "false" ]; then
    echo "Zipping output directory: ${output_dir_name}"
    zip -qry "${output_dir_name}".zip "${output_dir_name}"
    echo "Deleting output directory: ${output_dir_name}"
    rm -rf "${output_dir_name}"

    echo "ICDx support information has been created and zipped in the file:"
    echo "${output_dir_name}.zip"
else
    echo "ICDx support information has been created in the following directory:"
    echo "${output_dir_name}"
fi
