Skip to content

Instantly share code, notes, and snippets.

@rafliiar17
Last active December 23, 2025 08:58
Show Gist options
  • Select an option

  • Save rafliiar17/a18f8519c9689e525a4ebaea92b0b085 to your computer and use it in GitHub Desktop.

Select an option

Save rafliiar17/a18f8519c9689e525a4ebaea92b0b085 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Script Inventarisasi Server + Firewall Audit
# Output: Format TSV untuk Google Sheets
# Compatible: CentOS 5, 6, 7, 8 + Ubuntu + Debian
print_line() {
echo "=================================================================================="
}
print_header() {
echo ""
print_line
echo " $1"
print_line
}
clear
echo "INVENTARISASI SERVER & FIREWALL AUDIT"
echo "Generated: $(date '+%Y-%m-%d %H:%M:%S')"
echo "Hostname: $(hostname)"
print_line
# Check if running as root
if [ "$(id -u)" -ne 0 ]; then
echo ""
echo "WARNING: Not running as root. Some info may be incomplete."
echo " Run as root: sudo su -"
echo ""
sleep 2
fi
# ============================================================================
# COLLECT BASIC SERVER INFO
# ============================================================================
print_header "COLLECTING SERVER INFORMATION"
# Kode Area / Nama Server
NAMA_SERVER="${NAMA_SERVER:-$(hostname)}"
KODE_AREA="${KODE_AREA:-AUTO-$(hostname -s | tr '[:lower:]' '[:upper:]')}"
# Produk
PRODUK="${PRODUK:-General Server}"
# Nama Daerah
NAMA_DAERAH="${NAMA_DAERAH:-$(hostname -d 2>/dev/null || echo 'N/A')}"
if [ "$NAMA_DAERAH" = "localdomain" ] || [ "$NAMA_DAERAH" = "(none)" ]; then
NAMA_DAERAH="N/A"
fi
# Tipe Server
if [ -d /etc/vmware-tools ] || [ -d /usr/lib/vmware-tools ]; then
SERVER_TYPE="VM IDC"
elif [ -f /.dockerenv ]; then
SERVER_TYPE="Docker"
elif [ -d /proc/vz ]; then
SERVER_TYPE="VM (OpenVZ)"
elif [ -f /proc/xen/capabilities ]; then
SERVER_TYPE="VM (Xen)"
elif command -v systemd-detect-virt > /dev/null 2>&1; then
VIRT_TYPE=$(systemd-detect-virt 2>/dev/null)
if [ "$VIRT_TYPE" != "none" ]; then
SERVER_TYPE="VM ($VIRT_TYPE)"
else
SERVER_TYPE="Physical"
fi
else
SERVER_TYPE="Physical"
fi
# OS Version
if [ -f /etc/redhat-release ]; then
OS_VERSION=$(cat /etc/redhat-release)
# Detect Major Version for logic branching
if grep -q "release 7" /etc/redhat-release; then
OS_MAJOR=7
elif grep -q "release 6" /etc/redhat-release; then
OS_MAJOR=6
elif grep -q "release 5" /etc/redhat-release; then
OS_MAJOR=5
elif grep -q "release 8" /etc/redhat-release; then
OS_MAJOR=8
else
OS_MAJOR=0 # Unknown
fi
elif [ -f /etc/os-release ]; then
OS_VERSION=$(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2)
# Try to detect version from os-release
if grep -q "VERSION_ID=\"7" /etc/os-release; then
OS_MAJOR=7
elif grep -q "VERSION_ID=\"8" /etc/os-release; then
OS_MAJOR=8
else
OS_MAJOR=0
fi
else
OS_VERSION=$(uname -s)
OS_MAJOR=0
fi
# Kernel
KERNEL=$(uname -r)
# ============================================================================
# DETAILED CPU INFORMATION
# ============================================================================
CPU_CORES=$(grep -c processor /proc/cpuinfo)
CPU_MODEL=$(grep "model name" /proc/cpuinfo | head -1 | cut -d':' -f2 | sed 's/^[ \t]*//' | sed 's/ */ /g')
if [ -z "$CPU_MODEL" ]; then
CPU_MODEL="Unknown CPU"
fi
# Physical CPU count
PHYSICAL_CPU=$(grep "physical id" /proc/cpuinfo | sort -u | wc -l)
if [ "$PHYSICAL_CPU" -eq 0 ]; then
PHYSICAL_CPU=1
fi
CPU_INFO="${CPU_CORES} Core (${PHYSICAL_CPU} CPU) - ${CPU_MODEL}"
# ============================================================================
# DETAILED RAM INFORMATION
# ============================================================================
# Total RAM in GB
RAM_TOTAL_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}')
RAM_TOTAL_GB=$(echo "scale=2; $RAM_TOTAL_KB / 1024 / 1024" | bc)
RAM_TOTAL="${RAM_TOTAL_GB} GB"
# Try to get RAM details from dmidecode
RAM_DETAIL=""
if command -v dmidecode > /dev/null 2>&1 && [ "$(id -u)" -eq 0 ]; then
RAM_MODULES=$(dmidecode -t memory 2>/dev/null | grep -A 20 "Memory Device" | grep "Size:" | grep -v "No Module" | grep -v "^Size: 0" | wc -l)
RAM_SPEEDS=$(dmidecode -t memory 2>/dev/null | grep -A 20 "Memory Device" | grep "Speed:" | grep -v "Unknown" | grep -v "^Speed: 0" | head -1 | cut -d':' -f2 | sed 's/^[ \t]*//')
RAM_TYPE=$(dmidecode -t memory 2>/dev/null | grep -A 20 "Memory Device" | grep "Type:" | grep -v "Unknown" | grep -v "Type: <OUT OF SPEC>" | head -1 | cut -d':' -f2 | sed 's/^[ \t]*//')
if [ ! -z "$RAM_MODULES" ] && [ "$RAM_MODULES" -gt 0 ]; then
RAM_DETAIL="${RAM_MODULES}x modules"
if [ ! -z "$RAM_TYPE" ]; then
RAM_DETAIL="${RAM_DETAIL}, ${RAM_TYPE}"
fi
if [ ! -z "$RAM_SPEEDS" ]; then
RAM_DETAIL="${RAM_DETAIL}, ${RAM_SPEEDS}"
fi
fi
fi
if [ ! -z "$RAM_DETAIL" ]; then
RAM_INFO="${RAM_TOTAL} (${RAM_DETAIL})"
else
RAM_INFO="${RAM_TOTAL}"
fi
# ============================================================================
# DETAILED DISK INFORMATION
# ============================================================================
DISK_INFO=""
DISK_TOTAL_GB=0
# Get all disk devices
if command -v lsblk > /dev/null 2>&1; then
# Using lsblk (modern systems)
DISK_DEVICES=$(lsblk -d -n -o NAME,TYPE,SIZE,MODEL 2>/dev/null | grep disk)
while IFS= read -r line; do
DISK_NAME=$(echo "$line" | awk '{print $1}')
DISK_SIZE=$(echo "$line" | awk '{print $3}')
DISK_MODEL=$(echo "$line" | cut -d' ' -f4- | sed 's/^[ \t]*//')
if [ -z "$DISK_MODEL" ] || [ "$DISK_MODEL" = "disk" ]; then
DISK_MODEL="Unknown"
fi
# Convert size to GB for total calculation
SIZE_NUM=$(echo "$DISK_SIZE" | sed 's/[^0-9.]//g')
SIZE_UNIT=$(echo "$DISK_SIZE" | sed 's/[0-9.]//g')
case "$SIZE_UNIT" in
T|TB)
SIZE_GB=$(echo "scale=0; $SIZE_NUM * 1024" | bc)
;;
G|GB)
SIZE_GB=$(echo "scale=0; $SIZE_NUM / 1" | bc)
;;
*)
SIZE_GB=0
;;
esac
DISK_TOTAL_GB=$(echo "$DISK_TOTAL_GB + $SIZE_GB" | bc)
if [ -z "$DISK_INFO" ]; then
DISK_INFO="${DISK_SIZE} ${DISK_MODEL}"
else
DISK_INFO="${DISK_INFO}, ${DISK_SIZE} ${DISK_MODEL}"
fi
done <<< "$DISK_DEVICES"
else
# Fallback: use fdisk
if command -v fdisk > /dev/null 2>&1 && [ "$(id -u)" -eq 0 ]; then
DISK_DEVICES=$(fdisk -l 2>/dev/null | grep "^Disk /dev/" | grep -v "loop\|ram\|dm-")
while IFS= read -r line; do
DISK_NAME=$(echo "$line" | awk '{print $2}' | tr -d ':')
DISK_SIZE=$(echo "$line" | grep -oP '\d+(\.\d+)?\s*(G|T)B' | head -1)
if [ -z "$DISK_SIZE" ]; then
DISK_SIZE=$(echo "$line" | awk '{print $3$4}')
fi
# Try to get model from smartctl
DISK_MODEL="Unknown"
if command -v smartctl > /dev/null 2>&1; then
DISK_MODEL=$(smartctl -i "$DISK_NAME" 2>/dev/null | grep "Device Model\|Product:" | cut -d':' -f2 | sed 's/^[ \t]*//' | head -1)
fi
if [ -z "$DISK_MODEL" ] || [ "$DISK_MODEL" = "Unknown" ]; then
DISK_MODEL=$(basename "$DISK_NAME")
fi
if [ -z "$DISK_INFO" ]; then
DISK_INFO="${DISK_SIZE} ${DISK_MODEL}"
else
DISK_INFO="${DISK_INFO}, ${DISK_SIZE} ${DISK_MODEL}"
fi
done <<< "$DISK_DEVICES"
fi
fi
# Fallback if no disk info found
if [ -z "$DISK_INFO" ]; then
TOTAL_DISK=$(df -h --total 2>/dev/null | grep total | awk '{print $2}')
if [ -z "$TOTAL_DISK" ]; then
TOTAL_DISK=$(df -h / | tail -1 | awk '{print $2}')
fi
DISK_INFO="Total: $TOTAL_DISK"
else
# Add total
if [ $(echo "$DISK_TOTAL_GB > 1024" | bc) -eq 1 ]; then
DISK_TOTAL_TB=$(echo "scale=2; $DISK_TOTAL_GB / 1024" | bc)
DISK_INFO="${DISK_INFO} | Total: ${DISK_TOTAL_TB} TB"
else
DISK_INFO="${DISK_INFO} | Total: ${DISK_TOTAL_GB} GB"
fi
fi
# IP Address
if command -v ip > /dev/null 2>&1; then
PRIMARY_IP=$(ip addr show | grep "inet " | grep -v "127.0.0.1" | awk '{print $2}' | cut -d'/' -f1 | head -1)
else
PRIMARY_IP=$(ifconfig | grep "inet " | grep -v "127.0.0.1" | awk '{print $2}' | cut -d':' -f2 | head -1)
fi
# SSH Port
SSH_PORT=$(ss -tlnp 2>/dev/null | grep sshd | awk '{print $4}' | rev | cut -d':' -f1 | rev | head -1)
if [ -z "$SSH_PORT" ]; then
SSH_PORT=$(netstat -tlnp 2>/dev/null | grep sshd | awk '{print $4}' | rev | cut -d':' -f1 | rev | head -1)
fi
if [ -z "$SSH_PORT" ]; then
SSH_PORT="22"
fi
echo "Server Name : $NAMA_SERVER"
echo "Type : $SERVER_TYPE"
echo "OS : $OS_VERSION"
echo "CPU : $CPU_INFO"
echo "RAM : $RAM_INFO"
echo "Disk : $DISK_INFO"
echo "IP : $PRIMARY_IP"
echo "SSH Port : $SSH_PORT"
echo ""
# ============================================================================
# DETECT FIREWALL & GET ALLOWED PORTS
# ============================================================================
print_header "ANALYZING FIREWALL CONFIGURATION"
FIREWALL_TYPE="None"
ALL_PUBLIC_PORTS=""
ALL_RESTRICTED_PORTS=""
# Check Firewall based on OS Version
if [ "$OS_MAJOR" -eq 7 ] || [ "$OS_MAJOR" -eq 8 ]; then
# CentOS 7/8 - Default firewalld
if command -v firewall-cmd > /dev/null 2>&1 && systemctl is-active firewalld > /dev/null 2>&1; then
FIREWALL_TYPE="firewalld"
ACTIVE_ZONES=$(firewall-cmd --get-active-zones 2>/dev/null | grep -v "interfaces:" | grep -v "sources:")
echo "Firewall: firewalld (Active)"
echo "Active zones: $ACTIVE_ZONES"
ALLOWED_PORTS=""
# Loop through each active zone
for zone in $ACTIVE_ZONES; do
# Get ports from zone (preserve protocol)
ZONE_PORTS_RAW=$(firewall-cmd --zone=$zone --list-ports 2>/dev/null | tr ' ' '\n')
# Expand ranges if any
for zp in $ZONE_PORTS_RAW; do
if echo "$zp" | grep -q "-"; then
RANGE=${zp%/*}
PROTO=${zp#*/}
START=${RANGE%-*}
END=${RANGE#*-}
if command -v seq > /dev/null 2>&1; then
for p in $(seq $START $END); do
ALLOWED_PORTS="${ALLOWED_PORTS} ${p}/${PROTO}"
done
else
# Fallback if seq missing (rare on EL7)
ALLOWED_PORTS="${ALLOWED_PORTS} ${zp}"
fi
else
ALLOWED_PORTS="${ALLOWED_PORTS} ${zp}"
fi
done
# Get services from zone and convert to ports
SERVICES=$(firewall-cmd --zone=$zone --list-services 2>/dev/null)
for service in $SERVICES; do
P=""
# Try dynamic lookup first
DYN_PORTS=$(firewall-cmd --service="$service" --get-ports 2>/dev/null)
if [ ! -z "$DYN_PORTS" ]; then
# Remove newlines and add /protocol if missing (default tcp)
# Output is like "22/tcp" or "80/tcp 443/tcp" or just "123" (rare)
for dp in $DYN_PORTS; do
if echo "$dp" | grep -q "/"; then
ALLOWED_PORTS="${ALLOWED_PORTS} ${dp}"
else
ALLOWED_PORTS="${ALLOWED_PORTS} ${dp}/tcp"
fi
done
else
# Fallback to hardcoded defaults
case $service in
ssh) P="22/tcp" ;;
http) P="80/tcp" ;;
https) P="443/tcp" ;;
ftp) P="21/tcp" ;;
smtp) P="25/tcp" ;;
dns) P="53/udp" ;;
mysql) P="3306/tcp" ;;
postgresql) P="5432/tcp" ;;
ntp) P="123/udp" ;;
dhcpv6-client) P="546/udp" ;;
*) P="" ;;
esac
if [ ! -z "$P" ]; then ALLOWED_PORTS="${ALLOWED_PORTS} ${P}"; fi
fi
done
done
ALL_PUBLIC_PORTS=$(echo "$ALLOWED_PORTS" | tr ' ' '\n' | sort -u | uniq | tr '\n' ' ')
elif command -v iptables > /dev/null 2>&1; then
# Fallback to iptables if firewalld matches "iptables" usage (rare but possible)
# Using logic below
:
fi
fi
# CentOS 5/6 Logic (IPTables)
if [ "$OS_MAJOR" -eq 6 ] || [ "$OS_MAJOR" -eq 5 ]; then
# Older systems use iptables service
IPT_RUNNING=0
if service iptables status 2>/dev/null | grep -q "Table: filter"; then
IPT_RUNNING=1
elif service iptables status 2>/dev/null | grep -q "num target"; then
IPT_RUNNING=1
fi
if [ $IPT_RUNNING -eq 1 ] || command -v iptables > /dev/null 2>&1; then
FIREWALL_TYPE="iptables"
INPUT_POLICY=$(iptables -L INPUT -n | head -1 | grep -o "policy [A-Z]*" | awk '{print $2}')
if [ -z "$INPUT_POLICY" ]; then INPUT_POLICY="UNKNOWN"; fi
echo "Firewall: iptables (Active, Policy: $INPUT_POLICY)"
# Parse rules (Old Style for CentOS 6)
iptables -L INPUT -n 2>/dev/null | grep ACCEPT | grep tcp | while IFS= read -r rule; do
# Example: ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
PORT=$(echo "$rule" | grep -o "dpt:[0-9]*" | cut -d: -f2)
if [ ! -z "$PORT" ]; then
SOURCE=$(echo "$rule" | awk '{print $4}')
if [ "$SOURCE" = "0.0.0.0/0" ] || [ "$SOURCE" = "anywhere" ]; then
echo "${PORT}/tcp|PUBLIC" >> /tmp/fw_tmp.$$
else
echo "${PORT}/tcp|RESTRICTED" >> /tmp/fw_tmp.$$
fi
fi
done
if [ -f /tmp/fw_tmp.$$ ]; then
# Flatten with tr to ensure space separated list for grep checks
ALL_PUBLIC_PORTS=$(grep "|PUBLIC" /tmp/fw_tmp.$$ | cut -d'|' -f1 | sort -u | tr '\n' ' ')
rm -f /tmp/fw_tmp.$$
fi
# If Policy is ACCEPT, everything listening is technically open...
# ...UNLESS there is a catch-all REJECT/DROP rule at the end.
IS_PERMISSIVE=0
if [ "$INPUT_POLICY" = "ACCEPT" ]; then
IS_PERMISSIVE=1
# Check for catch-all reject/drop in modern syntax (-S)
# Looking for rules like "-A INPUT -j REJECT" with no source/dest restrictions
# We grep for REJECT/DROP, then ensure it's not specific (-s, -d, -i, -p)
# Note: This is an approximation. A rule at the end is usually the catch-all.
if iptables -S INPUT 2>/dev/null | grep -E "^-A INPUT -j (REJECT|DROP)" >/dev/null; then
IS_PERMISSIVE=0
fi
# Check for catch-all in old syntax (-L)
# Looking for target REJECT/DROP with source/dest 0.0.0.0/0 or anywhere
if [ $IS_PERMISSIVE -eq 1 ]; then
if iptables -L INPUT -n 2>/dev/null | grep -E "^(REJECT|DROP).*(0.0.0.0/0|anywhere).*(0.0.0.0/0|anywhere)" >/dev/null; then
IS_PERMISSIVE=0
fi
fi
fi
if [ $IS_PERMISSIVE -eq 1 ]; then
# Get all listening TCP ports (requires netstat, which we used for LISTENING earlier but maybe not available here)
# Use generic approach compatible with older CentOS
LISTENING_PORTS=""
if command -v netstat > /dev/null 2>&1; then
LISTENING_PORTS=$(netstat -tln | grep -E "^tcp" | awk '{print $4}' | awk -F: '{print $NF}' | sort -u)
elif command -v ss > /dev/null 2>&1; then
LISTENING_PORTS=$(ss -tlnH | awk '{print $4}' | awk -F: '{print $NF}' | sort -u)
fi
for lp in $LISTENING_PORTS; do
if echo " $ALL_PUBLIC_PORTS " | grep -qv " ${lp}/tcp "; then
ALL_PUBLIC_PORTS="${ALL_PUBLIC_PORTS} ${lp}/tcp"
fi
done
# Re-sort and uniq
ALL_PUBLIC_PORTS=$(echo "$ALL_PUBLIC_PORTS" | tr ' ' '\n' | sort -u | tr '\n' ' ')
fi
if [ "$INPUT_POLICY" = "ACCEPT" ] && [ -z "$ALL_PUBLIC_PORTS" ]; then
ALL_PUBLIC_PORTS="ALL (Policy ACCEPT)"
fi
fi
fi
# General Fallback / Unknown OS (Debian/Ubuntu/Etc)
if [ "$OS_MAJOR" -eq 0 ]; then
# Check UFW
if command -v ufw > /dev/null 2>&1; then
if ufw status 2>/dev/null | grep -q "Status: active"; then
FIREWALL_TYPE="ufw"
echo "Firewall: UFW (Active)"
ALL_PUBLIC_PORTS=$(ufw status 2>/dev/null | grep ALLOW | awk '{print $1}' | grep -E "^[0-9]+" | sort -u)
fi
fi
# Check raw iptables if no UFW
if [ "$FIREWALL_TYPE" = "None" ] && command -v iptables > /dev/null 2>&1; then
# Reuse iptables logic (assume modern syntax check first)
if iptables -S INPUT 2>/dev/null > /dev/null; then
FIREWALL_TYPE="iptables"
# ... reused parsing logic omitted for brevity, keeping simple for unknown ...
fi
fi
fi
if [ "$FIREWALL_TYPE" = "None" ]; then
echo "Firewall: Not Detected"
PORT_FW_OPEN="No Firewall"
else
# Format firewall ports
if [ "$ALL_PUBLIC_PORTS" = "ALL (Policy ACCEPT)" ]; then
PORT_FW_OPEN=" ALL PORTS OPEN (Policy ACCEPT)"
else
# Format as Table
HEADER=$(printf " %-15s %s" "PORT/PROTO" "SERVICE")
SEPARATOR=$(printf " %-15s %s" "----------" "-------")
PORT_FW_OPEN="${HEADER}\n${SEPARATOR}"
for pp in $ALL_PUBLIC_PORTS; do
P_NUM=${pp%/*}
P_PROTO=${pp#*/}
SNAME="Custom"
case $P_NUM in
22) SNAME="SSH" ;;
80) SNAME="HTTP" ;;
443) SNAME="HTTPS" ;;
21) SNAME="FTP" ;;
25) SNAME="SMTP" ;;
53) SNAME="DNS" ;;
123) SNAME="NTP" ;;
546) SNAME="DHCPv6" ;;
110) SNAME="POP3" ;;
143) SNAME="IMAP" ;;
3306) SNAME="MySQL/MariaDB" ;;
5432) SNAME="PostgreSQL" ;;
8080|8888|9000|9090) SNAME="Web Alternative" ;;
esac
ROW=$(printf " %-15s %s" "$pp" "$SNAME")
PORT_FW_OPEN="${PORT_FW_OPEN}\n${ROW}"
done
if [ -z "$ALL_PUBLIC_PORTS" ]; then # Check if ALL_PUBLIC_PORTS is empty after loop
PORT_FW_OPEN="None"
fi
fi
fi
echo "Public Ports : $PORT_FW_OPEN"
echo ""
# ============================================================================
# DETECT WEB SERVICES & URLs
# ============================================================================
print_header "DETECTING WEB SERVICES"
URL_LOCAL=""
URL_PUBLIC=""
# Check web server
# Get listening ports for verification
if command -v ss > /dev/null 2>&1; then
LISTENING=$(ss -tlnp 2>/dev/null | grep LISTEN | awk '{print $4}' | rev | cut -d':' -f1 | rev | sort -nu)
else
LISTENING=$(netstat -tlnp 2>/dev/null | grep LISTEN | awk '{print $4}' | rev | cut -d':' -f1 | rev | sort -nu)
fi
# Check Web Service based on OS
WEB_RUNNING=0
# Define status check function based on OS
check_web_status() {
local service_name=$1
if [ "$OS_MAJOR" -eq 7 ] || [ "$OS_MAJOR" -eq 8 ]; then
systemctl is-active "$service_name" > /dev/null 2>&1
return $?
elif [ "$OS_MAJOR" -eq 6 ] || [ "$OS_MAJOR" -eq 5 ]; then
if service "$service_name" status 2>/dev/null | grep -q "running"; then
return 0
fi
return 1
else
# Fallback
if command -v systemctl > /dev/null 2>&1; then
systemctl is-active "$service_name" > /dev/null 2>&1
elif service "$service_name" status 2>/dev/null | grep -q "running"; then
return 0
fi
fi
}
if check_web_status "httpd"; then
WEB_RUNNING=1
elif check_web_status "apache2"; then
WEB_RUNNING=1
elif check_web_status "nginx"; then
WEB_RUNNING=1
fi
if [ $WEB_RUNNING -eq 1 ]; then
# Check if port 80 or 443 is listening
if command -v ss > /dev/null 2>&1; then
HTTP_LISTENING=$(ss -tlnp 2>/dev/null | grep ":80 " | wc -l)
HTTPS_LISTENING=$(ss -tlnp 2>/dev/null | grep ":443 " | wc -l)
else
HTTP_LISTENING=$(netstat -tlnp 2>/dev/null | grep ":80 " | wc -l)
HTTPS_LISTENING=$(netstat -tlnp 2>/dev/null | grep ":443 " | wc -l)
fi
# Initialize basic URLs (will be appended/replaced by detailed ones if found)
BASE_URL_LOCAL=""
if [ $HTTPS_LISTENING -gt 0 ]; then
BASE_URL_LOCAL="https://${PRIMARY_IP}"
URL_PUBLIC="https://$(hostname -f 2>/dev/null || hostname)"
elif [ $HTTP_LISTENING -gt 0 ]; then
BASE_URL_LOCAL="http://${PRIMARY_IP}"
URL_PUBLIC="http://$(hostname -f 2>/dev/null || hostname)"
fi
fi
# Extra check for httpd.conf defined ports AND VHosts
NB_APACHE_PORTS=""
APACHE_CMD=""
if command -v httpd > /dev/null 2>&1; then
APACHE_CMD="httpd"
elif command -v apache2 > /dev/null 2>&1; then
APACHE_CMD="apache2"
elif command -v apachectl > /dev/null 2>&1; then
APACHE_CMD="apachectl"
elif [ -x /usr/sbin/httpd ]; then
APACHE_CMD="/usr/sbin/httpd"
elif [ -x /usr/sbin/apache2 ]; then
APACHE_CMD="/usr/sbin/apache2"
fi
if [ ! -z "$APACHE_CMD" ] && [ "$(id -u)" -eq 0 ]; then
# Parse VHost output
# Format: *:9061 PALEMBANG-PBB-BPHTB (/etc/httpd/conf/httpd.conf:362)
# _default_:443 DEMO_V-TAX (/etc/httpd/conf.d/ssl.conf:74)
# We want port (9061) and name (PALEMBANG-PBB-BPHTB)
# Parse VHost output using simplest grep to avoid version issues
$APACHE_CMD -S 2>/dev/null | grep ":[0-9]" | while read -r line; do
# Clean line
line=$(echo "$line" | sed 's/^[ \t]*//')
# Skip informational lines
if echo "$line" | grep -q "is a NameVirtualHost"; then continue; fi
if echo "$line" | grep -q "default server"; then continue; fi
# Extract port (col 1, strip anything before last :)
COL1=$(echo "$line" | awk '{print $1}')
# Handle cases like "port 80 namevhost" -> COL1="port", COL2="80"
if [ "$COL1" = "port" ]; then
APORT=$(echo "$line" | awk '{print $2}')
else
APORT=$(echo "$COL1" | rev | cut -d':' -f1 | rev)
fi
# Validate integer
if ! [[ "$APORT" =~ ^[0-9]+$ ]]; then continue; fi
# Try to get App Name from DocumentRoot
# Config info is usually the last field: (/etc/httpd/conf/httpd.conf:123)
CONFIG_DATA=$(echo "$line" | awk '{print $NF}' | tr -d '()')
CONFIG_FILE=${CONFIG_DATA%:*}
START_LINE=${CONFIG_DATA##*:}
ANAME="Unknown"
FOUND_DOCROOT=0
if [ -n "$CONFIG_FILE" ] && [ -f "$CONFIG_FILE" ] && [[ "$START_LINE" =~ ^[0-9]+$ ]]; then
# Read 50 lines from start line to look for DocumentRoot
DOCROOT_LINE=$(sed -n "${START_LINE},$(($START_LINE + 100))p" "$CONFIG_FILE" | grep -i "DocumentRoot" | head -1)
if [ -n "$DOCROOT_LINE" ]; then
# Extract path. Format: DocumentRoot "/var/www/html/pbb"
DOCROOT_PATH=$(echo "$DOCROOT_LINE" | awk '{print $2}' | tr -d '"' | tr -d "'")
if [ -n "$DOCROOT_PATH" ]; then
ANAME=$(basename "$DOCROOT_PATH")
FOUND_DOCROOT=1
fi
fi
fi
# Fallback to ServerName if DocRoot retrieval failed
if [ $FOUND_DOCROOT -eq 0 ]; then
if [ "$COL1" = "port" ]; then
ANAME=$(echo "$line" | awk '{print $3}')
else
ANAME=$(echo "$line" | awk '{print $2}')
fi
if [ -z "$ANAME" ] || [[ "$ANAME" == \(* ]]; then ANAME="default"; fi
fi
# Check if allowed in firewall
IS_ALLOWED=0
if echo " $ALL_PUBLIC_PORTS " | grep -q " ${APORT}/"; then
IS_ALLOWED=1
elif [ "$ALL_PUBLIC_PORTS" = "ALL OPEN" ] || [ "$FIREWALL_TYPE" = "None" ]; then
IS_ALLOWED=1
fi
# Trust httpd -S configuration if firewall allows it (removed IS_LISTENING check for VHosts)
if [ $IS_ALLOWED -eq 1 ]; then
# Construct URL Table Row
PROTO="http"
if [ "$APORT" = "443" ] || [ "$APORT" = "8443" ]; then PROTO="https"; fi
URL="${PROTO}://${PRIMARY_IP}:${APORT}"
# Format: Port Name URL
# Use a fixed width simple table
# PORT(5) NAME(20) URL(...)
# Use printf -v to store in variable instead of subshell capturing if possible,
# but here standard assignment is fine.
# Avoid duplicates in URL_LOCAL
if echo "$URL_LOCAL" | grep -qv "$APORT"; then
# Prepare row content
ROW=$(printf " %-8s %-25s %s" "$APORT" "${ANAME:0:24}" "$URL")
if [ -z "$URL_LOCAL" ] || [ "$URL_LOCAL" = "N/A" ]; then
HEADER=$(printf " %-8s %-25s %s" "PORT" "APP NAME" "URL")
SEPARATOR=$(printf " %-8s %-25s %s" "----" "--------" "---")
URL_LOCAL="${HEADER}\n${SEPARATOR}\n${ROW}"
else
URL_LOCAL="${URL_LOCAL}\n${ROW}"
fi
fi
fi
# Write to temp file to persist variable change outside pipe
echo "$URL_LOCAL" > /tmp/url_local_tmp.$$
done
if [ -f /tmp/url_local_tmp.$$ ]; then
URL_LOCAL=$(cat /tmp/url_local_tmp.$$ | tail -1)
rm -f /tmp/url_local_tmp.$$
fi
fi
# Use base if detailed is empty, otherwise check for duplicates
if [ -z "$URL_LOCAL" ]; then
URL_LOCAL="$BASE_URL_LOCAL"
elif [ ! -z "$BASE_URL_LOCAL" ]; then
# If URL_LOCAL contains detailed info, we might want to skip the generic BASE_URL_LOCAL if it's redundant
# Check if BASE_URL_LOCAL is already covered (e.g., https://IP is covered by https://IP:443...)
# For now, just prepend base if not present? Or relies on VHosts providing all?
# If 2 out of 3 Vhosts are found, we still want those.
# User complained about duplication: "https://IP, https://IP:443..."
# If we have VHOST defined for 443, we don't need generic https://IP.
# Simple heuristic: If URL_LOCAL has content, don't show generic BASE_URL unless it's on a port not covered?
# Actually, let's just NOT add BASE_URL_LOCAL if URL_LOCAL was populated by VHosts/Ports.
:
fi
# Fallback to simple port parsing if no VHost detected or cmd failed, but keeping it simple for now as requested specific vhost logic
# If simple ports were added previously, we might want to keep the loop for non-vhost ports too?
# The user wants "localhost:9080 name-server", so we prioritize VHost name.
# If URL is still empty/NA, try basic config scrape again for ports not in VHost?
# For now, let's mix the logic:
if [ -z "$URL_LOCAL" ] || [ "$URL_LOCAL" = "N/A" ]; then
# Logic from before (fallback)
if [ -f /etc/httpd/conf/httpd.conf ]; then
NB_APACHE_PORTS=$(grep -E "^Listen [0-9]+" /etc/httpd/conf/httpd.conf | awk '{print $2}')
elif [ -f /etc/apache2/ports.conf ]; then
NB_APACHE_PORTS=$(grep -E "^Listen [0-9]+" /etc/apache2/ports.conf | awk '{print $2}')
fi
# ... (rest of old loop could go here if really needed, but VHost -S is comprehensive if apache is running)
# Re-implementing the simple loop just in case:
for aport in $NB_APACHE_PORTS; do
aport=$(echo $aport | tr -d ' ')
if [ -z "$aport" ]; then continue; fi
if [ "$aport" = "80" ] || [ "$aport" = "443" ]; then continue; fi
IS_ALLOWED=0
if echo " $ALL_PUBLIC_PORTS " | grep -q " ${aport}/"; then IS_ALLOWED=1; fi
if [ "$ALL_PUBLIC_PORTS" = "ALL OPEN" ] || [ "$FIREWALL_TYPE" = "None" ]; then IS_ALLOWED=1; fi
if [ $IS_ALLOWED -eq 1 ] && echo "$LISTENING" | grep -qw "$aport"; then
if [ -z "$URL_LOCAL" ] || [ "$URL_LOCAL" = "N/A" ]; then
URL_LOCAL="http://${PRIMARY_IP}:${aport}"
else
URL_LOCAL="${URL_LOCAL}, http://${PRIMARY_IP}:${aport}"
fi
fi
done
fi
if [ -z "$URL_LOCAL" ]; then
URL_LOCAL="N/A"
fi
if [ -z "$URL_PUBLIC" ]; then
URL_PUBLIC="N/A"
fi
echo "Web Service : $([ $WEB_RUNNING -eq 1 ] && echo 'Running' || echo 'Not Running')"
echo "URL Local : $URL_LOCAL"
echo "URL Public : $URL_PUBLIC"
echo ""
# ============================================================================
# CHECK CONNECTIVITY (INBOUND/OUTBOUND)
# ============================================================================
print_header "CHECKING CONNECTIVITY"
# Outbound Internet (Public)
OUTBOUND_PUBLIC="NO"
if ping -c 1 -W 2 8.8.8.8 > /dev/null 2>&1; then
OUTBOUND_PUBLIC="YES"
fi
# Database Driven Connectivity Check
DB_CONNECTIVITY_REPORT=""
if command -v mysql > /dev/null 2>&1; then
# Database Credentials (Change here to avoid prompt)
DB_USER="sw_user"
DB_PASS="sw_pwd"
# Try to connect
echo "Database: Connectivity Check..."
# Prompt for password if not set
if [ -z "$DB_PASS" ]; then
echo "Please enter password for MySQL user '$DB_USER' (press Enter if none or ~/.my.cnf exists):"
read -s -p "Password: " DB_PASS
echo ""
fi
QUERY="SELECT DISTINCT SUBSTRING_INDEX(CTR_AC_VALUE, '/', 3) FROM SW_PBB.CENTRAL_APP_CONFIG a WHERE a.CTR_AC_KEY IN ('ESIGN_URL_CALLBACK', 'ESIGN_API_URL', 'PORTLET_LINK', 'URL_PUBLIK', 'ESIGN_MASSAL_API_URL', 'ESIGN_SKNJOP_URL', 'qris', 'va') AND CTR_AC_VALUE IS NOT NULL AND CTR_AC_VALUE <> '' AND (CTR_AC_VALUE LIKE 'http://%' OR CTR_AC_VALUE LIKE 'https://%') AND CTR_AC_VALUE NOT LIKE 'http://localhost%' AND CTR_AC_VALUE NOT LIKE 'https://localhost%' AND CTR_AC_VALUE NOT LIKE 'http://127.0.0.1%' AND CTR_AC_VALUE NOT LIKE 'https://127.0.0.1%';"
# Get URLs (Raw mode, No Headers) with explicit credentials
if [ -z "$DB_PASS" ]; then
# Try without -p first if empty (socket/config)
DB_URLS=$(mysql -u"$DB_USER" -N -B -e "$QUERY" 2>/dev/null)
else
DB_URLS=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -B -e "$QUERY" 2>/dev/null)
fi
if [ ! -z "$DB_URLS" ]; then
DB_CONNECTIVITY_REPORT=" Database Configured Connectivity:"
for url in $DB_URLS; do
# Check with curl (3s timeout, Head request)
if curl -I -s -m 3 "$url" > /dev/null 2>&1; then
STATUS="OK"
else
STATUS="FAIL/UNREACHABLE"
fi
# Clean URL for display
CLEAN_URL=$(echo "$url" | tr -d '\r')
DB_CONNECTIVITY_REPORT="${DB_CONNECTIVITY_REPORT}\n - $CLEAN_URL : $STATUS"
done
else
DB_CONNECTIVITY_REPORT=" Database Configured Connectivity: No external URLs found (or auth failed)."
fi
else
DB_CONNECTIVITY_REPORT=" Database Configured Connectivity: Skipped (MySQL client not found)"
fi
if [ -z "$DB_CONNECTIVITY_REPORT" ] && command -v mysql > /dev/null 2>&1; then
DB_CONNECTIVITY_REPORT=" Database Configured Connectivity: Skipped (Cannot connect to MySQL - check ~/.my.cnf or root auth)"
fi
# Outbound HTTPS
if command -v curl > /dev/null 2>&1; then
if curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 "https://www.google.com" 2>/dev/null | grep -q "^[23]"; then
OUTBOUND_PUBLIC="YES (HTTPS)"
fi
fi
# Inbound Public - check if any public port is accessible
INBOUND_PUBLIC="UNKNOWN"
if [ ! -z "$ALL_PUBLIC_PORTS" ] && [ "$ALL_PUBLIC_PORTS" != "None" ]; then
if [ "$ALL_PUBLIC_PORTS" = "ALL (Policy ACCEPT)" ] || [ "$ALL_PUBLIC_PORTS" = "ALL OPEN" ]; then
INBOUND_PUBLIC="YES (All Ports)"
else
PORT_COUNT=$(echo "$ALL_PUBLIC_PORTS" | wc -w)
if [ $PORT_COUNT -gt 0 ]; then
INBOUND_PUBLIC="YES ($PORT_COUNT ports)"
else
INBOUND_PUBLIC="NO"
fi
fi
else
INBOUND_PUBLIC="NO (Firewall)"
fi
# Inbound Intranet - assume YES if server is accessible locally
INBOUND_INTRA="YES"
# Outbound Intranet - assume YES
OUTBOUND_INTRA="YES"
echo "Outbound Internet : $OUTBOUND_PUBLIC"
echo "Inbound Internet : $INBOUND_PUBLIC"
echo ""
# ============================================================================
# DETAILED FIREWALL PORT LIST
# ============================================================================
if [ ! -z "$ALL_PUBLIC_PORTS" ] && [ "$ALL_PUBLIC_PORTS" != "None" ] && [ "$ALL_PUBLIC_PORTS" != "ALL OPEN" ] && [ "$ALL_PUBLIC_PORTS" != "ALL (Policy ACCEPT)" ]; then
print_header "FIREWALL PORT DETAILS"
echo ""
echo "Port Service Status"
print_line
# Get listening ports
if command -v ss > /dev/null 2>&1; then
LISTENING=$(ss -tlnp 2>/dev/null | grep LISTEN | awk '{print $4}' | rev | cut -d':' -f1 | rev | sort -nu)
else
LISTENING=$(netstat -tlnp 2>/dev/null | grep LISTEN | awk '{print $4}' | rev | cut -d':' -f1 | rev | sort -nu)
fi
# Echo ALL_PUBLIC_PORTS could be newlines
for item in $ALL_PUBLIC_PORTS; do
PORT=${item%%/*}
PROTO=${item##*/}
# Get service name
case $PORT in
22) SERVICE="SSH" ;;
80) SERVICE="HTTP" ;;
443) SERVICE="HTTPS" ;;
3306) SERVICE="MySQL" ;;
5432) SERVICE="PostgreSQL" ;;
8080) SERVICE="HTTP Alt" ;;
8443) SERVICE="HTTPS Alt" ;;
*) SERVICE="Custom" ;;
esac
# Check if listening - remove /tcp etc
if echo "$LISTENING" | grep -qw "$PORT"; then
STATUS="Listening"
else
STATUS="Not Listening"
fi
printf "%-9s %-17s %s\n" "$item" "$SERVICE" "$STATUS"
done
echo ""
fi
# ============================================================================
# SUMMARY
# ============================================================================
print_header "SUMMARY"
echo ""
echo "Server Information:"
echo " Nama/Hostname : $NAMA_SERVER"
echo " Produk : $PRODUK"
echo " Nama Daerah : $NAMA_DAERAH"
echo " Tipe Server : $SERVER_TYPE"
echo " OS : $OS_VERSION"
echo " IP Address : $PRIMARY_IP"
echo ""
echo "Hardware Specifications:"
echo " CPU : $CPU_INFO"
echo " RAM : $RAM_INFO"
echo " Disk : $DISK_INFO"
echo ""
echo "Network & Firewall:"
echo " SSH Port : $SSH_PORT"
echo " Firewall Type : $FIREWALL_TYPE"
if echo "$PORT_FW_OPEN" | grep -q "\n"; then
echo " FW Open Ports :"
echo -e "$PORT_FW_OPEN"
else
echo " FW Open Ports : $PORT_FW_OPEN"
fi
echo ""
echo "Web Application:"
if echo "$URL_LOCAL" | grep -q "\n"; then
echo " URL Local :"
echo " ---------------"
echo -e "$URL_LOCAL"
else
echo " URL Local : $URL_LOCAL"
fi
echo " URL Public : $URL_PUBLIC"
echo ""
echo "Connectivity:"
echo " Outbound Intra : $OUTBOUND_INTRA"
echo " Outbound Inter : $OUTBOUND_PUBLIC"
echo " Inbound Intra : $INBOUND_INTRA"
echo " Inbound Public : $INBOUND_PUBLIC"
if [ ! -z "$DB_CONNECTIVITY_REPORT" ]; then
echo -e "$DB_CONNECTIVITY_REPORT"
fi
echo ""
print_line
echo "INVENTARISASI SELESAI"
echo ""
echo "Cara menyimpan report:"
echo " 1. Full report : $0 > inventory_$(hostname)_$(date +%Y%m%d).txt"
echo " 2. TSV only : $0 | grep -A 1 'PRODUK.*NAMA DAERAH' > inventory.tsv"
echo ""
print_line
@rafliiar17
Copy link
Author

first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment