#!/bin/bash PORT=8080 DB="/usr/share/GeoIP/GeoLite2-Country.mmdb" LOGFILE="/dev/null" COUNTRY_FILE="countries.txt" declare -A COUNTRY_COUNT declare -A SEEN declare -A COUNTRY_NAME # --- Parse -N flag (e.g. -10 means show top 10) --- TOPN=0 if [[ "$1" =~ ^-([0-9]+)$ ]]; then TOPN="${BASH_REMATCH[1]}" fi # --- Load external country list --- while IFS='=' read -r ISO NAME; do [[ -z "$ISO" ]] && continue COUNTRY_NAME["$ISO"]="$NAME" done < "$COUNTRY_FILE" echo "Monitoring port $PORT..." echo "Updating table every 5 seconds." [[ $TOPN -gt 0 ]] && echo "Showing only Top $TOPN countries." LAST_REFRESH=0 while true; do # FAST LOOP: collect new connections IPS=$(ss -tn sport = :$PORT | awk 'NR>1 {print $5}' | cut -d: -f1) for IP in $IPS; do [[ "$IP" == "127.0.0.1" ]] && continue if [[ -z "${SEEN[$IP]}" ]]; then SEEN[$IP]=1 RAW=$(mmdblookup --file "$DB" --ip "$IP" country iso_code 2>/dev/null) ISO=$(echo "$RAW" | grep -oE '[A-Z]{2}') [[ -z "$ISO" ]] && ISO="UNKNOWN" COUNTRY_COUNT["$ISO"]=$(( COUNTRY_COUNT["$ISO"] + 1 )) NAME="${COUNTRY_NAME[$ISO]}" [[ -z "$NAME" ]] && NAME="Unknown Country" echo "$(date '+%F %T') - $IP - $ISO ($NAME)" >> "$LOGFILE" fi done # SLOW LOOP: refresh display every 5 seconds NOW=$(date +%s) if (( NOW - LAST_REFRESH >= 5 )); then LAST_REFRESH=$NOW clear echo "=== Live GeoIP Stats (Port $PORT) ===" echo "(Updated: $(date '+%H:%M:%S'))" echo # Sort by count (descending) SORTED=$(for ISO in "${!COUNTRY_COUNT[@]}"; do echo "${COUNTRY_COUNT[$ISO]} $ISO" done | sort -rn) COUNT=0 while read -r LINE; do NUM=$(echo "$LINE" | awk '{print $1}') ISO=$(echo "$LINE" | awk '{print $2}') NAME="${COUNTRY_NAME[$ISO]}" [[ -z "$NAME" ]] && NAME="Unknown Country" echo "$ISO ($NAME): $NUM" ((COUNT++)) [[ $TOPN -gt 0 && $COUNT -ge $TOPN ]] && break done <<< "$SORTED" fi sleep 0.1 done