Sistem Operasi Ubuntu Server 20.04 lts s/d Ubuntu Server 24.04 lts
Instal conntrack (jika belum ada). Ini adalah alat penting untuk memutus koneksi secara paksa.
sudo apt update && sudo apt install conntrack -y
Pastikan tool kalkulasi (bc) terinstall (biasanya sudah ada, tapi ini untuk jaga-jaga):
sudo apt install bc -y
Jalan kan perintah berikut :
sudo mkdir -p /opt/udp-proxy/bin
sudo mkdir -p /opt/udp-proxy/log
Langkah 2: Membuat Skrip Utama Penjaga
1.Buat file skrip:
sudo nano /opt/udp-proxy/bin/enforcer_service.sh
2.Salin dan tempel seluruh skrip di bawah ini.
#!/bin/bash
# =================================================================
# --- CEK FILE BENDERA (PANEL KONTROL) ---
# =================================================================
FLAG_FILE="/opt/udp-proxy/log/enforcer.enabled"
if [ ! -f "$FLAG_FILE" ]; then
echo "[$(date)] File bendera '$FLAG_FILE' tidak ditemukan. Penjaga tidak aktif. Keluar."
exit 0
fi
# =================================================================
# --- KONFIGURASI PENJAGA ---
# =================================================================
PROTECTED_PORT=36712
STATE_FILE="/opt/udp-proxy/log/enforcer_state.log"
STATE_LOCK="/opt/udp-proxy/log/enforcer_state.lock"
IPTABLES_CHAIN="UDP_ENFORCER"
BANDWIDTH_LOG="/opt/udp-proxy/log/bandwidth_usage.log"
MEMORY_MINUTES=10
TIMEOUT_MINUTES=15
GRACE_PERIOD_SECONDS=0
UDP_SERVICE_NAME="udp-custom.service"
### [NEW] KONFIGURASI AUTO-UNBLOCK 5 MENIT ###
BLOCKED_IP_FILE="/opt/udp-proxy/log/blocked_ips.log"
BLOCKED_IP_LOCK="/opt/udp-proxy/log/blocked_ips.lock"
# Set berapa MENIT IP akan diblokir sebelum otomatis dilepas
# Set 0 untuk PERMANEN (tidak pernah auto-lepas)
UNBLOCK_AFTER_MINUTES=5
BANDWIDTH_CHAIN="UDP_BW_COUNTER"
FLUSH_QUEUE="/opt/udp-proxy/log/bw_flush_queue.log"
FLUSH_LOCK="/opt/udp-proxy/log/bw_flush_queue.lock"
ACCUMULATOR_FILE="/opt/udp-proxy/log/bw_accumulator.log"
ACCUMULATOR_LOCK="/opt/udp-proxy/log/bw_accumulator.lock"
HISTORY_1H_FILE="/opt/udp-proxy/log/bw_history_1h.log"
HISTORY_LOCK="/opt/udp-proxy/log/bw_history_1h.lock"
### Buku Harian 24 Jam ###
DAILY_LOG_DIR="/opt/udp-proxy/log/daily"
DAILY_STATE="/opt/udp-proxy/log/daily_state.log"
DAILY_STATE_LOCK="/opt/udp-proxy/log/daily_state.lock"
DAILY_LEDGER="/opt/udp-proxy/log/bw_daily_ledger.log"
DAILY_LEDGER_LOCK="/opt/udp-proxy/log/bw_daily_ledger.lock"
# =================================================================
# Buat direktori dan file yang diperlukan
mkdir -p "$(dirname "$STATE_FILE")"
mkdir -p "$(dirname "$BANDWIDTH_LOG")"
mkdir -p "$DAILY_LOG_DIR"
touch "$STATE_FILE" "$BANDWIDTH_LOG" "$FLUSH_QUEUE" "$ACCUMULATOR_FILE"
touch "$HISTORY_1H_FILE" "$DAILY_STATE" "$DAILY_LEDGER"
touch "$STATE_LOCK" "$FLUSH_LOCK" "$ACCUMULATOR_LOCK" "$HISTORY_LOCK"
touch "$DAILY_STATE_LOCK" "$DAILY_LEDGER_LOCK"
touch "$BLOCKED_IP_FILE" "$BLOCKED_IP_LOCK"
# =================================================================
# --- FUNGSI LOCKING ---
# =================================================================
LOCK_TIMEOUT=10
acquire_lock() {
local lock_file="$1"
local count=0
while [ -f "$lock_file" ]; do
local lock_pid=$(cat "$lock_file" 2>/dev/null)
if [ -n "$lock_pid" ] && ! kill -0 "$lock_pid" 2>/dev/null; then
rm -f "$lock_file"
break
fi
sleep 0.1
count=$((count + 1))
if [ "$count" -gt $((LOCK_TIMEOUT * 10)) ]; then
rm -f "$lock_file"
break
fi
done
echo $$ > "$lock_file"
}
release_lock() {
local lock_file="$1"
local lock_pid=$(cat "$lock_file" 2>/dev/null)
if [ "$lock_pid" = "$$" ]; then
rm -f "$lock_file"
fi
}
# =================================================================
# --- FUNGSI CATAT IP TERBLOKIR ---
# =================================================================
function record_blocked_ip() {
local user="$1"
local ip="$2"
# Jika UNBLOCK_AFTER_MINUTES = 0, tidak perlu catat (permanen)
if [ "$UNBLOCK_AFTER_MINUTES" -eq 0 ]; then return; fi
local current_time=$(date +%s)
acquire_lock "$BLOCKED_IP_LOCK"
local temp_file=$(mktemp)
grep -v "^${ip}:" "$BLOCKED_IP_FILE" > "$temp_file" 2>/dev/null
echo "${ip}:${user}:${current_time}" >> "$temp_file"
mv "$temp_file" "$BLOCKED_IP_FILE"
release_lock "$BLOCKED_IP_LOCK"
}
# =================================================================
# --- FUNGSI AUTO-UNBLOCK ---
# =================================================================
function auto_unblock() {
# Jika UNBLOCK_AFTER_MINUTES = 0, skip
if [ "$UNBLOCK_AFTER_MINUTES" -eq 0 ]; then return; fi
local current_time=$(date +%s)
local unblock_after_seconds=$((UNBLOCK_AFTER_MINUTES * 60))
local temp_file=$(mktemp)
local unblock_count=0
acquire_lock "$BLOCKED_IP_LOCK"
while IFS=':' read -r ip user block_time; do
if [[ -z "$ip" || -z "$block_time" ]]; then continue; fi
if ! [[ "$block_time" =~ ^[0-9]+$ ]]; then continue; fi
local elapsed=$((current_time - block_time))
if [ "$elapsed" -ge "$unblock_after_seconds" ]; then
echo "[$(date)] >>> AUTO-UNBLOCK: Hukuman $UNBLOCK_AFTER_MINUTES menit habis. Melepas IP '$ip' (user: '$user')..."
local rule_num=$(sudo iptables -L "$IPTABLES_CHAIN" --line-numbers -n 2>/dev/null | grep -w "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
sudo iptables -D "$IPTABLES_CHAIN" "$rule_num" 2>/dev/null
unblock_count=$((unblock_count + 1))
fi
else
echo "${ip}:${user}:${block_time}" >> "$temp_file"
fi
done < "$BLOCKED_IP_FILE"
mv "$temp_file" "$BLOCKED_IP_FILE"
release_lock "$BLOCKED_IP_LOCK"
if [ "$unblock_count" -gt 0 ]; then
echo "[$(date)] Auto-unblock: $unblock_count IP telah dilepas setelah $UNBLOCK_AFTER_MINUTES menit."
fi
}
# =================================================================
# --- FUNGSI PEMBERSIH ---
# =================================================================
function cleanup() {
echo "[$(date)] =====> MEMULAI PEMBERSIHAN DAN EKSEKUSI TIMER <====="
local current_time=$(date +%s)
local timeout_seconds=$((TIMEOUT_MINUTES * 60))
local temp_state_file=$(mktemp)
acquire_lock "$STATE_LOCK"
while IFS=':' read -r user ip last_seen violation_time; do
if [[ -z "$user" || -z "$ip" || -z "$last_seen" ]]; then continue; fi
if ! [[ "$last_seen" =~ ^[0-9]+$ ]]; then continue; fi
local elapsed=$((current_time - last_seen))
if [ "$elapsed" -lt "$timeout_seconds" ]; then
if [[ -n "$violation_time" && "$violation_time" =~ ^[0-9]+$ ]]; then
local violation_elapsed=$((current_time - violation_time))
if [ "$violation_elapsed" -ge "$GRACE_PERIOD_SECONDS" ]; then
echo "[$(date)] >>> EKSEKUSI: Timer habis. Memutus & memblokir IP '$ip' (user: '$user')..."
sudo conntrack -D -s "$ip" -p udp 2>/dev/null
if ! sudo iptables -C "$IPTABLES_CHAIN" -s "$ip" -j DROP &>/dev/null; then
sudo iptables -A "$IPTABLES_CHAIN" -s "$ip" -j DROP -m comment --comment "Kicked $user on $(date +%F-%T)" 2>/dev/null
fi
queue_flush_bandwidth "$user" "$ip"
record_blocked_ip "$user" "$ip"
continue
else
echo "${user}:${ip}:${last_seen}:${violation_time}" >> "$temp_state_file"
fi
else
echo "${user}:${ip}:${last_seen}:" >> "$temp_state_file"
fi
else
echo "[$(date)] Sesi untuk user '$user' dari IP '$ip' kadaluarsa. Membuka blokir..."
local rule_num=$(sudo iptables -L "$IPTABLES_CHAIN" --line-numbers -n 2>/dev/null | grep -w "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
sudo iptables -D "$IPTABLES_CHAIN" "$rule_num" 2>/dev/null
fi
queue_flush_bandwidth "$user" "$ip"
fi
done < "$STATE_FILE"
mv "$temp_state_file" "$STATE_FILE"
release_lock "$STATE_LOCK"
# Jalankan auto-unblock setelah cleanup
auto_unblock
echo "[$(date)] =====> PEMBERSIHAN SELESAI <====="
}
# =================================================================
# --- FUNGSI BLOCKING SEGERA ---
# =================================================================
function immediate_block() {
local user="$1"
local old_ip="$2"
echo "[$(date)] >>> EKSEKUSI SEGERA: Memutus & memblokir IP '$old_ip' (user: '$user')..."
sudo conntrack -D -s "$old_ip" -p udp 2>/dev/null
if ! sudo iptables -C "$IPTABLES_CHAIN" -s "$old_ip" -j DROP &>/dev/null; then
sudo iptables -A "$IPTABLES_CHAIN" -s "$old_ip" -j DROP -m comment --comment "Kicked $user on $(date +%F-%T)" 2>/dev/null
fi
queue_flush_bandwidth "$user" "$old_ip"
record_blocked_ip "$user" "$old_ip"
}
# =================================================================
# --- FUNGSI BANDWIDTH ---
# =================================================================
function add_bandwidth_counter() {
local ip="$1"
local user="$2"
if ! sudo iptables -C "$BANDWIDTH_CHAIN" -s "$ip" -p udp -j RETURN -m comment --comment "user:$user" &>/dev/null; then
sudo iptables -A "$BANDWIDTH_CHAIN" -s "$ip" -p udp -j RETURN -m comment --comment "user:$user" 2>/dev/null
fi
}
function queue_flush_bandwidth() {
local user="$1"
local ip="$2"
acquire_lock "$FLUSH_LOCK"
echo "$user $ip" >> "$FLUSH_QUEUE"
release_lock "$FLUSH_LOCK"
}
function update_daily_ledger() {
local user="$1"
local bytes="$2"
if [[ -z "$user" || -z "$bytes" || ! "$bytes" =~ ^[0-9]+$ ]]; then return; fi
acquire_lock "$DAILY_LEDGER_LOCK"
if [ -f "$DAILY_LEDGER" ] && grep -q "^${user}:" "$DAILY_LEDGER" 2>/dev/null; then
local temp_file=$(mktemp)
awk -F':' -v u="$user" -v b="$bytes" '$1 == u {print $1":"($2+b)} $1 != u' "$DAILY_LEDGER" > "$temp_file"
mv "$temp_file" "$DAILY_LEDGER"
else
echo "${user}:${bytes}" >> "$DAILY_LEDGER"
fi
release_lock "$DAILY_LEDGER_LOCK"
}
function monitor_bandwidth() {
local current_time=$(date +%s)
local today_date=$(date +%F)
local time_5m_ago=$((current_time - 300))
local time_1h_ago=$((current_time - 3600))
local time_limit_history=$((current_time - 3900))
acquire_lock "$DAILY_STATE_LOCK"
local last_day=$(cat "$DAILY_STATE" 2>/dev/null)
if [[ -n "$last_day" && "$today_date" != "$last_day" ]]; then
echo "[$(date)] >>> TUTUP BUKU HARIAN: Mengarsipkan seluruh data $last_day..."
if [ -s "$DAILY_LEDGER" ]; then
mv "$DAILY_LEDGER" "$DAILY_LOG_DIR/${last_day}.log"
else
touch "$DAILY_LOG_DIR/${last_day}.log"
fi
: > "$ACCUMULATOR_FILE"
: > "$HISTORY_1H_FILE"
: > "$DAILY_LEDGER"
echo "$today_date" > "$DAILY_STATE"
elif [[ -z "$last_day" ]]; then
echo "$today_date" > "$DAILY_STATE"
fi
release_lock "$DAILY_STATE_LOCK"
local temp_iptables=$(mktemp)
local temp_active_users=$(mktemp)
sudo iptables -L "$BANDWIDTH_CHAIN" -v -n -x 2>/dev/null > "$temp_iptables"
grep "user:" "$temp_iptables" 2>/dev/null | grep -oP 'user:\K[^ ]+' | sort -u > "$temp_active_users"
acquire_lock "$FLUSH_LOCK"
if [ -s "$FLUSH_QUEUE" ]; then
local temp_queue=$(mktemp)
cp "$FLUSH_QUEUE" "$temp_queue"
: > "$FLUSH_QUEUE"
release_lock "$FLUSH_LOCK"
while read -r user ip; do
if [[ -z "$user" || -z "$ip" ]]; then continue; fi
echo "$user" >> "$temp_active_users"
local bytes=$(grep -w "$ip" "$temp_iptables" 2>/dev/null | awk '{print $2}')
if [[ -n "$bytes" && "$bytes" =~ ^[0-9]+$ && "$bytes" -gt 0 ]]; then
acquire_lock "$ACCUMULATOR_LOCK"
if grep -q "^${user}:" "$ACCUMULATOR_FILE" 2>/dev/null; then
local temp_acc=$(mktemp)
awk -F':' -v u="$user" -v b="$bytes" -v t="$current_time" '$1 == u {print $1":"($2+b)":"t} $1 != u' "$ACCUMULATOR_FILE" > "$temp_acc"
mv "$temp_acc" "$ACCUMULATOR_FILE"
else
echo "${user}:${bytes}:${current_time}" >> "$ACCUMULATOR_FILE"
fi
release_lock "$ACCUMULATOR_LOCK"
update_daily_ledger "$user" "$bytes"
else
acquire_lock "$ACCUMULATOR_LOCK"
local temp_acc=$(mktemp)
awk -F':' -v u="$user" -v t="$current_time" '$1 == u {print $1":"$2":"t} $1 != u' "$ACCUMULATOR_FILE" > "$temp_acc"
mv "$temp_acc" "$ACCUMULATOR_FILE"
release_lock "$ACCUMULATOR_LOCK"
fi
local rule_num=$(sudo iptables -L "$BANDWIDTH_CHAIN" --line-numbers -n 2>/dev/null | grep -w "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
sudo iptables -D "$BANDWIDTH_CHAIN" "$rule_num" 2>/dev/null
fi
done < "$temp_queue"
rm -f "$temp_queue"
else
release_lock "$FLUSH_LOCK"
fi
while read -r line; do
local user=$(echo "$line" | grep -oP 'user:\K[^ ]+')
local bytes=$(echo "$line" | awk '{print $2}')
if [[ -n "$user" && -n "$bytes" && "$bytes" =~ ^[0-9]+$ ]]; then
acquire_lock "$ACCUMULATOR_LOCK"
if grep -q "^${user}:" "$ACCUMULATOR_FILE" 2>/dev/null; then
local temp_acc=$(mktemp)
awk -F':' -v u="$user" -v b="$bytes" -v t="$current_time" '$1 == u {print $1":"($2+b)":"t} $1 != u' "$ACCUMULATOR_FILE" > "$temp_acc"
mv "$temp_acc" "$ACCUMULATOR_FILE"
else
echo "${user}:${bytes}:${current_time}" >> "$ACCUMULATOR_FILE"
fi
release_lock "$ACCUMULATOR_LOCK"
update_daily_ledger "$user" "$bytes"
fi
done < <(grep "user:" "$temp_iptables" 2>/dev/null)
sudo iptables -Z "$BANDWIDTH_CHAIN" &>/dev/null
local temp_history=$(mktemp)
acquire_lock "$ACCUMULATOR_LOCK"
while IFS=':' read -r user bytes last_active; do
if [[ -n "$user" && -n "$bytes" ]]; then
echo "${current_time}:${user}:${bytes}" >> "$temp_history"
fi
done < "$ACCUMULATOR_FILE"
release_lock "$ACCUMULATOR_LOCK"
acquire_lock "$HISTORY_LOCK"
if [ -f "$HISTORY_1H_FILE" ] && [ -s "$HISTORY_1H_FILE" ]; then
cat "$HISTORY_1H_FILE" "$temp_history" | awk -v limit="$time_limit_history" '$1 >= limit' > "${temp_history}.merged"
mv "${temp_history}.merged" "$HISTORY_1H_FILE"
else
mv "$temp_history" "$HISTORY_1H_FILE"
fi
release_lock "$HISTORY_LOCK"
local temp_acc_clean=$(mktemp)
sort -u "$temp_active_users" > "${temp_active_users}.uniq"
acquire_lock "$ACCUMULATOR_LOCK"
while IFS=':' read -r user bytes last_active; do
if [[ -z "$user" ]]; then continue; fi
if grep -qx "$user" "${temp_active_users}.uniq" 2>/dev/null; then
echo "${user}:${bytes}:${last_active}" >> "$temp_acc_clean"
elif [[ -n "$last_active" && "$last_active" =~ ^[0-9]+$ && "$last_active" -gt "$time_1h_ago" ]]; then
echo "${user}:${bytes}:${last_active}" >> "$temp_acc_clean"
fi
done < "$ACCUMULATOR_FILE"
mv "$temp_acc_clean" "$ACCUMULATOR_FILE"
release_lock "$ACCUMULATOR_LOCK"
{
echo "============================================================"
echo " LAPORAN BANDWIDTH AKUMULASI USER - $(date '+%Y-%m-%d %H:%M:%S')"
echo "============================================================"
printf "%-15s %14s %14s %12s\n" "USER" "5_MIN(MB)" "1_HOUR(MB)" "AVG(Mbps)"
echo "------------------------------------------------------------"
acquire_lock "$ACCUMULATOR_LOCK"
acquire_lock "$HISTORY_LOCK"
while IFS=':' read -r user bytes_now last_active; do
if [[ -z "$user" || -z "$bytes_now" ]]; then continue; fi
local bytes_5m_ago=$(grep ".*:${user}:" "$HISTORY_1H_FILE" 2>/dev/null | awk -F':' -v limit="$time_5m_ago" '$1 <= limit {print $3}' | tail -n 1)
if [ -z "$bytes_5m_ago" ] || ! [[ "$bytes_5m_ago" =~ ^[0-9]+$ ]]; then bytes_5m_ago=0; fi
local bytes_1h_ago=$(grep ".*:${user}:" "$HISTORY_1H_FILE" 2>/dev/null | awk -F':' -v limit="$time_1h_ago" '$1 <= limit {print $3}' | tail -n 1)
if [ -z "$bytes_1h_ago" ] || ! [[ "$bytes_1h_ago" =~ ^[0-9]+$ ]]; then bytes_1h_ago=0; fi
local diff_5m=$((bytes_now - bytes_5m_ago))
if [ "$diff_5m" -lt 0 ]; then diff_5m=0; fi
local diff_1h=$((bytes_now - bytes_1h_ago))
if [ "$diff_1h" -lt 0 ]; then diff_1h=0; fi
local mb_5m=$(echo "scale=2; $diff_5m / 1048576" | bc 2>/dev/null || echo "0.00")
local mb_1h=$(echo "scale=2; $diff_1h / 1048576" | bc 2>/dev/null || echo "0.00")
local mbps=$(echo "scale=2; ($diff_5m * 8) / 3000000" | bc 2>/dev/null || echo "0.00")
printf "%-15s %14s %14s %12s\n" "$user" "$mb_5m" "$mb_1h" "$mbps"
done < "$ACCUMULATOR_FILE"
release_lock "$HISTORY_LOCK"
release_lock "$ACCUMULATOR_LOCK"
echo "============================================================"
echo "Catatan: User tetap tampil 1 jam setelah terakhir terhubung"
echo "============================================================"
} | tee "$BANDWIDTH_LOG"
rm -f "$temp_iptables" "$temp_active_users" "${temp_active_users}.uniq" "$temp_history" 2>/dev/null
}
# =================================================================
# --- INISIALISASI PENJAGA ---
# =================================================================
if ! sudo iptables -L "$IPTABLES_CHAIN" &>/dev/null; then
sudo iptables -N "$IPTABLES_CHAIN" 2>/dev/null
fi
if ! sudo iptables -L "$BANDWIDTH_CHAIN" &>/dev/null; then
sudo iptables -N "$BANDWIDTH_CHAIN" 2>/dev/null
else
sudo iptables -L "$BANDWIDTH_CHAIN" -v -n -x 2>/dev/null | grep "user:" | while read -r line; do
user=$(echo "$line" | grep -oP 'user:\K[^ ]+')
ip=$(echo "$line" | awk '{print $8}')
if [[ -n "$user" && -n "$ip" ]]; then
queue_flush_bandwidth "$user" "$ip"
fi
done
fi
echo "[$(date)] Memastikan aturan iptables berada di posisi teratas..."
sudo iptables -D INPUT -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" 2>/dev/null
sudo iptables -D FORWARD -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" 2>/dev/null
sudo iptables -D INPUT -p udp --dport "$PROTECTED_PORT" -j "$BANDWIDTH_CHAIN" 2>/dev/null
sudo iptables -F "$IPTABLES_CHAIN" 2>/dev/null
sudo iptables -I INPUT 1 -p udp --dport "$PROTECTED_PORT" -j "$BANDWIDTH_CHAIN" 2>/dev/null
sudo iptables -I INPUT 2 -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" 2>/dev/null
sudo iptables -I FORWARD 1 -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" 2>/dev/null
# Bersihkan file blocked_ips saat service start (karena iptables sudah di-flush)
: > "$BLOCKED_IP_FILE"
# =================================================================
# --- JALANKAN PROSES BACKGROUND ---
# =================================================================
cleanup_handler() {
echo "[$(date)] Menerima sinyal shutdown, menghentikan proses background..."
[ -n "$CLEANUP_PID" ] && kill "$CLEANUP_PID" 2>/dev/null
[ -n "$BANDWIDTH_PID" ] && kill "$BANDWIDTH_PID" 2>/dev/null
rm -f "$STATE_LOCK" "$FLUSH_LOCK" "$ACCUMULATOR_LOCK" "$HISTORY_LOCK" "$DAILY_STATE_LOCK" "$DAILY_LEDGER_LOCK" "$BLOCKED_IP_LOCK"
echo "[$(date)] Penjaga berhenti dengan bersih."
exit 0
}
trap cleanup_handler SIGTERM SIGINT EXIT
while true; do cleanup; sleep 60; done &
CLEANUP_PID=$!
while true; do monitor_bandwidth; sleep 300; done &
BANDWIDTH_PID=$!
echo "[$(date)] Memuat memori awal dari $MEMORY_MINUTES menit terakhir..."
sudo journalctl -u "$UDP_SERVICE_NAME" --since "$MEMORY_MINUTES minutes ago" --no-pager 2>/dev/null | grep "Client connected" | sort | awk -F'[][]' '
{
for (i=1; i<=NF; i++) {
if ($i ~ /src:/) { split($i, s, ":"); ip = s[2]; }
if ($i ~ /user:/) { split($i, u, ":"); user = u[2]; }
}
if (user && ip) print user ":" ip ":" systime() ":" > "'"$STATE_FILE"'"
}'
local_temp=$(mktemp)
sort -u "$STATE_FILE" > "$local_temp" 2>/dev/null
mv "$local_temp" "$STATE_FILE"
while IFS=':' read -r user ip last_seen violation_time; do
if [[ -n "$user" && -n "$ip" ]]; then
add_bandwidth_counter "$ip" "$user"
fi
done < "$STATE_FILE"
echo "[$(date)] Memori awal selesai. Penjaga siap bertugas!"
echo "[$(date)] Konfigurasi Auto-Unblock: $UNBLOCK_AFTER_MINUTES menit (0 = permanen)"
echo "[$(date)] Memantau log layanan: $UDP_SERVICE_NAME"
sudo journalctl -u "$UDP_SERVICE_NAME" -f --no-tail 2>/dev/null | while read line; do
if [[ "$line" == *"[INFO]"*"[src:"*"[user:"*"Client connected"* ]]; then
IP=$(echo "$line" | awk -F'[][]' '{for(i=1;i<=NF;i++){if($i ~ /src:/){split($i, a, ":"); print a[2]}}}')
USER=$(echo "$line" | awk -F'[][]' '{for(i=1;i<=NF;i++){if($i ~ /user:/){split($i, a, ":"); print a[2]}}}')
if [[ -n "$IP" && -n "$USER" ]]; then
echo "[$(date)] Koneksi baru: User '$USER' dari IP '$IP'"
add_bandwidth_counter "$IP" "$USER"
acquire_lock "$STATE_LOCK"
LAST_ENTRY=$(grep "^${USER}:" "$STATE_FILE" | tail -n 1)
LAST_IP=$(echo "$LAST_ENTRY" | cut -d':' -f2)
if [[ -n "$LAST_IP" && "$LAST_IP" != "$IP" ]]; then
echo "[$(date)] >>> PELANGGARAN: User '$USER' multi-login (IP lama: '$LAST_IP', IP baru: '$IP')."
release_lock "$STATE_LOCK"
immediate_block "$USER" "$LAST_IP"
acquire_lock "$STATE_LOCK"
local_temp=$(mktemp)
grep -v "^${USER}:${LAST_IP}:" "$STATE_FILE" > "$local_temp"
mv "$local_temp" "$STATE_FILE"
fi
echo "${USER}:${IP}:$(date +%s)::" >> "$STATE_FILE"
local_temp=$(mktemp)
sort -u "$STATE_FILE" > "$local_temp"
mv "$local_temp" "$STATE_FILE"
release_lock "$STATE_LOCK"
fi
elif [[ "$line" == *"[INFO]"*"[src:"*"[user:"*"Client disconnected"* ]]; then
IP=$(echo "$line" | awk -F'[][]' '{for(i=1;i<=NF;i++){if($i ~ /src:/){split($i, a, ":"); print a[2]}}}')
USER=$(echo "$line" | awk -F'[][]' '{for(i=1;i<=NF;i++){if($i ~ /user:/){split($i, a, ":"); print a[2]}}}')
if [[ -n "$IP" && -n "$USER" ]]; then
echo "[$(date)] User '$USER' dari IP '$IP' disconnect. Memasukkan antrian riwayat..."
queue_flush_bandwidth "$USER" "$IP"
acquire_lock "$STATE_LOCK"
local_temp=$(mktemp)
grep -v "^${USER}:${IP}:" "$STATE_FILE" > "$local_temp"
mv "$local_temp" "$STATE_FILE"
release_lock "$STATE_LOCK"
fi
fi
done
4.Berikan izin eksekusi:
sudo chmod +x /opt/udp-proxy/bin/enforcer_service.sh
Langkah 3: Membuat Layanan systemd
1.Buat file layanan:
sudo nano /etc/systemd/system/udp-enforcer.service
2.Salin dan tempel konfigurasi berikut:
[Unit]
Description=UDP Enforcer Service
After=network.target udp-custom.service
[Service]
Type=simple
ExecStart=/opt/udp-proxy/bin/enforcer_service.sh
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
3.Simpan dan keluar (Ctrl+X, Y, Enter).
Catatan :
Perintah di bawah ini hanya di gunakan untuk mengedit Layanan systemd saja. Jika tidak , Jangan Gunakan !!! Lewati langkah ini dan lanjutkan ke Langkah 4: Membuat Perintah Kontrol Manual (enforcer-on / enforcer-off) .
Perintah Untuk Mengedit Layanan systemd
sudo nano /etc/systemd/system/udp-enforcer.service
# Paste konfigurasi atau Edit konfigurasi, lalu Simpan dan keluar (Ctrl+X, Y, Enter)
# Jalan kan satu persatu perintah ini :
sudo systemctl daemon-reload
sudo systemctl enable udp-enforcer.service
sudo systemctl restart udp-enforcer.service
Langkah 4: Membuat Perintah Kontrol Manual (enforcer-on / enforcer-off)
Ini adalah kunci untuk kontrol yang "ber-ingat".
1.Buat perintah enforcer-on:
sudo nano /usr/local/bin/enforcer-on
Salin dan tempel:
#!/bin/bash
FLAG_FILE="/opt/udp-proxy/log/enforcer.enabled"
SERVICE_NAME="udp-enforcer.service"
echo "Mengaktifkan Penjaga Koneksi..."
# Buat direktori log jika belum ada untuk mencegah error
sudo mkdir -p "$(dirname "$FLAG_FILE")"
sudo touch "$FLAG_FILE"
sudo systemctl start "$SERVICE_NAME"
sudo systemctl enable "$SERVICE_NAME"
echo "Penjaga telah diaktifkan. Statusnya akan diingat setelah reboot."
2.Buat perintah enforcer-off:
sudo nano /usr/local/bin/enforcer-off
Salin dan tempel:
#!/bin/bash
FLAG_FILE="/opt/udp-proxy/log/enforcer.enabled"
SERVICE_NAME="udp-enforcer.service"
echo "Menonaktifkan Penjaga Koneksi..."
sudo systemctl stop "$SERVICE_NAME"
sudo rm -f "$FLAG_FILE"
echo "Penjaga telah dinonaktifkan. Statusnya akan diingat setelah reboot."
3.Berikan izin eksekusi pada kedua perintah:
sudo chmod +x /usr/local/bin/enforcer-on
sudo chmod +x /usr/local/bin/enforcer-off
5.Langkah 5: Finalisasi dan Aktivasi Awal
Langkah terakhir untuk menyelesaikan setup dan mengaktifkan Penjaga untuk pertama kalinya.
1.Muat ulang systemd untuk mengenali layanan baru:
sudo systemctl daemon-reload
2.Aktifkan layanan sekali saja
sudo systemctl enable udp-enforcer.service
3.Aktifkan Penjaga untuk pertama kalinya:
enforcer-on
4.Verifikasi statusnya:
sudo systemctl status udp-enforcer.service
Anda harus melihat Active: active (running).
Jalankan perintah-perintah ini secara manual untuk pengecekan urutan aturan:
sudo iptables -D INPUT -p udp --dport 36712 -j UDP_ENFORCER
sudo iptables -I INPUT 1 -p udp --dport 36712 -j UDP_ENFORCER
Sekarang, coba lagi perintah :
sudo iptables -L INPUT -n -v --line-numbers
Hasilnya harusnya terlihat seperti ini:
Chain INPUT (policy ACCEPT ...)
num pkts bytes target prot opt in out source destination
1 0 0 UDP_ENFORCER udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:36712
2 1355K 318M ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 udp dpt:36712
...
Sekarang UDP_ENFORCER ada di posisi #1. Sistem blokir seharusnya sudah bekerja!
Restart layanan untuk menerapkan perubahan:
sudo systemctl restart udp-enforcer.service
Ringkasan Perintah Tanpa Panel/Manual
Mengaktifkan Penjaga
enforcer-on
Menonaktifkan Penjaga
enforcer-off
Cek Status Layanan
sudo systemctl status udp-enforcer.service
Lihat Log Aktivitas
sudo journalctl -u udp-enforcer.service -f --no-pager
Lihat IP yang Diblokir
sudo iptables -L UDP_ENFORCER -n -v
Lepas Semua Blokir
sudo iptables -F UDP_ENFORCER
Hapus File State (Reset)
echo "" > /opt/udp-proxy/log/enforcer_state.log




