#!/usr/bin/bash
#
# HENCSAT Packet Recorder
# Copyright (C) 2019-2026 by Thomas Dreibholz
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact: dreibh@simula.no

# Bash options:
set -eu


# Ensure running as root
if [ "$(id -u)" != "0" ]; then
  exec sudo "$0" "$@"
fi

PID_FILE="/var/run/HENCSAT-Packet-Recorder.pid"

TCPDUMP_COMMAND="tcpdump"
TCPDUMP_OPTIONS="-i any -s 65536 -n -p"   # NOTE: -p => not using promiscuous mode!
TCPDUMP_FILTER='(ip or ip6 or arp) and (not (tcp port 22))'


# ###### Write log information ##############################################
log ()
{
   echo -e "\x1b[1;34m$(date +%FT%H:%M:%S): $*\x1b[0m"
}


# ###### Write log action information #######################################
log-action ()
{
   echo -en "\x1b[34m$(date +%FT%H:%M:%S): $*\x1b[0m"
}


# ###### Write log result information #######################################
RESULT_GOOD=1
RESULT_BAD=0
_BadResults=0
log-result ()
{
   local result="$1"
   local line=120

   if [ "${result}" = "${RESULT_GOOD}" ] ; then
      echo -en "\x1b[${line}G\x1b[32mOK\x1b[0m\n"
   elif [ "${result}" = "${RESULT_BAD}" ] ; then
      echo -en "\x1b[${line}G\x1b[30;47;5mFAILED!\x1b[0m\n"
      _BadResults=$((_BadResults + 1))
   elif [ "${result}" = "" ] ; then
      echo >&2 "ERROR: No result given for log-result?!"
      exit 1
   else
      echo -en "\x1b[${line}G\x1b[0m${result}\n"
   fi
}


# ###### Start Packet Recorder ##############################################
packet-recorder-start ()
{
   outputFile="$1"

   # ------ Stop tcpdump, if it is still running ----------------------------
   packet-recorder-stop quiet

   # ------ Start tcpdump ---------------------------------------------------
   log-action "Starting HENCSAT Packet Recorder ..."
   # shellcheck disable=SC2015
   (
      nohup ${TCPDUMP_COMMAND} "${TCPDUMP_OPTIONS}" -w "${outputFile}" "${TCPDUMP_FILTER}" >/dev/null 2>&1 &
      echo "$!" >${PID_FILE}
      sleep 1
   ) && log-result ${RESULT_GOOD} || log-result ${RESULT_BAD}
}


# ###### Check Packet Recorder status #######################################
packet-recorder-status ()
{
   if [ -e "${PID_FILE}" ] ; then
      pid=$(cat ${PID_FILE})
      if ps -p "$pid"  | grep -q "${TCPDUMP_COMMAND}" ; then
         log "HENCSAT Packet Recorder is running with PID ${pid}"
      else
         log "HENCSAT Packet Recorder should be running with PID ${pid}, but it is gone!"
      fi
   else
      log "HENCSAT Packet Recorder is not running!"
   fi
}


# ###### Stop Packet Recorder ###############################################
packet-recorder-stop ()
{
   local quietMode="$1"

   if [ -e "${PID_FILE}" ] ; then
      pid=$(cat ${PID_FILE})
      if [ "${quietMode}" != "quiet" ] ; then
         log-action "Stopping HENCSAT Packet Recorder (PID ${pid}) ..."
      fi

      # ------ Send SIGINT --------------------------------------------------
      ps -p "$pid"  | grep -q "${TCPDUMP_COMMAND}" && kill -INT "${pid}" >/dev/null && \
      if [ "${quietMode}" != "quiet" ] ; then log-result ${RESULT_GOOD} || log-result ${RESULT_BAD} ; fi

      # ------ Wait for proper shutdown (up to 60s) -------------------------
      i=0
      while ps -p "$pid"  | grep -q "${TCPDUMP_COMMAND}" ; do
         sleep 1
         i=$((i + 1))
         if [ $i -ge 60 ] ; then
            kill -KILL "${pid}"
            break
         fi
      done

      rm -f ${PID_FILE}
   fi
}



# ###### Main program #######################################################

# ====== Configuration checks ===============================================
if [ $# -lt 1 ] ; then
   echo >&2 "Usage: $0 [[start output_file]|status|stop]"
   exit 1
fi


# ====== Start or Change ====================================================
action="$1"
if [ "${action}" = "start" ] ; then
   if [ $# -ge 2 ] ; then
      outputFile="$2"
      if [ ! -d "$(dirname "${outputFile}")" ] ; then
         echo >&2 "ERROR: Directory $(dirname "${outputFile}") for output file ${outputFile} does not exist!"
         exit 1
      fi
      packet-recorder-start "${outputFile}"
   else
      echo >&2 "ERROR: Not enough parameters for \"${action}\" given!"
      exit 1
   fi

# ====== Info ===============================================================
elif [ "${action}" = "status" ] ; then
   packet-recorder-status

# ====== Stop ===============================================================
elif [ "${action}" = "stop" ] ; then
   packet-recorder-stop

# ====== Error ==============================================================
else
   echo >&2 "ERROR: Unknown command \"${action}\"!"
   exit 1
fi
