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
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 (KONTROL MANUAL) ---
# =================================================================
FLAG_FILE="/opt/udp-proxy/log/enforcer.enabled"
if [ ! -f "$FLAG_FILE" ]; then
echo "[$(date)] File bendera '$FLAG_FILE' tidak ditemukan. Penjaga tidak akan dijalankan."
exit 0
fi
# =================================================================
# --- KONFIGURASI PENJAGA ---
# =================================================================
PROTECTED_PORT=36712
STATE_FILE="/opt/udp-proxy/log/enforcer_state.log"
IPTABLES_CHAIN="UDP_ENFORCER"
MEMORY_MINUTES=10
TIMEOUT_MINUTES=15
GRACE_PERIOD_SECONDS=120 # 2 menit = 120 detik
# =================================================================
# --- FUNGSI PEMBERSIH (OTOMATIS LUPA & EKSEKUSI TIMER) ---
# =================================================================
function cleanup() {
echo "[$(date)] Memulai pembersihan sesi dan pengecekan timer..."
local current_time=$(date +%s)
local timeout_seconds=$((TIMEOUT_MINUTES * 60))
local temp_state_file=$(mktemp)
if [ ! -f "$STATE_FILE" ]; then
touch "$STATE_FILE"
return
fi
while IFS=':' read -r user ip last_seen violation_time; do
if [[ -z "$user" || -z "$ip" || -z "$last_seen" ]]; then continue; fi
local elapsed=$((current_time - last_seen))
if [ "$elapsed" -lt "$timeout_seconds" ]; then
# Sesi masih aktif, periksa apakah ada timer yang perlu dieksekusi
if [[ -n "$violation_time" ]]; then
local violation_elapsed=$((current_time - violation_time))
if [ "$violation_elapsed" -ge "$GRACE_PERIOD_SECONDS" ]; then
echo "[$(date)] Timer habis. Menendang IP '$ip' untuk user '$user'..."
local rule_num=$(sudo iptables -L "$IPTABLES_CHAIN" --line-numbers -n | grep "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
sudo iptables -D "$IPTABLES_CHAIN" "$rule_num"
echo "[$(date)] Aturan untuk IP '$ip' telah dihapus dari iptables."
fi
# Jangan tambahkan kembali ke file state, karena sudah ditendang
continue
else
# Timer belum habis, simpan kembali dengan timer
echo "${user}:${ip}:${last_seen}:${violation_time}" >> "$temp_state_file"
fi
else
# Tidak ada timer, simpan kembali seperti biasa
echo "${user}:${ip}:${last_seen}:" >> "$temp_state_file"
fi
else
# Sesi sudah kadaluarsa, bersihkan
echo "[$(date)] Sesi untuk user '$user' dari IP '$ip' telah kadaluarsa. Membuka blokir..."
local rule_num=$(sudo iptables -L "$IPTABLES_CHAIN" --line-numbers -n | grep "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
sudo iptables -D "$IPTABLES_CHAIN" "$rule_num"
echo "[$(date)] Aturan untuk IP '$ip' telah dihapus dari iptables."
fi
fi
done < "$STATE_FILE"
mv "$temp_state_file" "$STATE_FILE"
}
#!/bin/bash
# =================================================================
# --- CEK FILE BENDERA (KONTROL MANUAL) ---
# =================================================================
FLAG_FILE="/opt/udp-proxy/log/enforcer.enabled"
if [ ! -f "$FLAG_FILE" ]; then
echo "[$(date)] File bendera '$FLAG_FILE' tidak ditemukan. Penjaga tidak akan dijalankan."
exit 0
fi
# =================================================================
# --- KONFIGURASI PENJAGA ---
# =================================================================
PROTECTED_PORT=36712
STATE_FILE="/opt/udp-proxy/log/enforcer_state.log"
IPTABLES_CHAIN="UDP_ENFORCER"
MEMORY_MINUTES=10
TIMEOUT_MINUTES=15
GRACE_PERIOD_SECONDS=120 # 2 menit = 120 detik
# =================================================================
# --- FUNGSI PEMBERSIH (OTOMATIS LUPA & EKSEKUSI TIMER) ---
# =================================================================
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)
if [ ! -f "$STATE_FILE" ]; then
touch "$STATE_FILE"
return
fi
while IFS=':' read -r user ip last_seen violation_time; do
if [[ -z "$user" || -z "$ip" || -z "$last_seen" ]]; then continue; fi
local elapsed=$((current_time - last_seen))
if [ "$elapsed" -lt "$timeout_seconds" ]; then
if [[ -n "$violation_time" ]]; then
local violation_elapsed=$((current_time - violation_time))
if [ "$violation_elapsed" -ge "$GRACE_PERIOD_SECONDS" ]; then
echo "[$(date)] >>> EKSEKUSI: Timer habis. Memutus koneksi IP '$ip' untuk user '$user'..."
# --- PERUBAHAN KRUSIAL 1: CONNTRACK AGRESIF ---
# Hapus SEMUA sesi UDP dari IP sumber, tanpa memandang port.
# Ini jauh lebih efektif untuk memutus koneksi.
echo "[$(date)] [DEBUG] Menjalankan: sudo conntrack -D -s $ip -p udp"
sudo conntrack -D -s "$ip" -p udp 2>/dev/null
# --- PERUBAHAN KRUSIAL 2: BLOKIR DI INPUT & FORWARD ---
# Kita blokir di kedua chain untuk memastikan tidak ada celah.
echo "[$(date)] [DEBUG] Memeriksa aturan iptables untuk IP '$ip'..."
if ! sudo iptables -C "$IPTABLES_CHAIN" -s "$ip" -j DROP &> /dev/null; then
echo "[$(date)] [DEBUG] Menjalankan: sudo iptables -A $IPTABLES_CHAIN -s $ip -j DROP"
sudo iptables -A "$IPTABLES_CHAIN" -s "$ip" -j DROP -m comment --comment "Kicked $USER on $(date +%F-%T)"
echo "[$(date)] >>> IP '$ip' telah diblokir di iptables."
else
echo "[$(date)] [DEBUG] Aturan DROP untuk IP '$ip' sudah ada."
fi
echo "[$(date)] >>> Eksekusi selesai untuk IP '$ip'."
continue
else
echo "[$(date)] [DEBUG] Timer untuk IP '$ip' user '$user' belum habis. Menunggu..."
echo "${user}:${ip}:${last_seen}:${violation_time}" >> "$temp_state_file"
fi
else
echo "[$(date)] [DEBUG] Sesi normal untuk user '$user' dari IP '$ip'."
echo "${user}:${ip}:${last_seen}:" >> "$temp_state_file"
fi
else
echo "[$(date)] Sesi untuk user '$user' dari IP '$ip' telah kadaluarsa. Membuka blokir..."
local rule_num=$(sudo iptables -L "$IPTABLES_CHAIN" --line-numbers -n | grep "$ip" | awk '{print $1}' | head -n 1)
if [ -n "$rule_num" ]; then
echo "[$(date)] [DEBUG] Menghapus aturan iptables nomor $rule_num untuk IP '$ip'."
sudo iptables -D "$IPTABLES_CHAIN" "$rule_num"
fi
fi
done < "$STATE_FILE"
mv "$temp_state_file" "$STATE_FILE"
echo "[$(date)] =====> PEMBERSIHAN SELESAI <====="
}
# =================================================================
# --- INISIALISASI PENJAGA ---
# =================================================================
mkdir -p "$(dirname "$STATE_FILE")"
touch "$STATE_FILE"
# Buat chain jika belum ada
if ! sudo iptables -L "$IPTABLES_CHAIN" &> /dev/null; then
echo "Membuat chain iptables: $IPTABLES_CHAIN"
sudo iptables -N "$IPTABLES_CHAIN"
fi
# Hubungkan ke INPUT chain
if ! sudo iptables -C INPUT -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" &> /dev/null; then
echo "Menghubungkan chain ke INPUT untuk port $PROTECTED_PORT"
sudo iptables -I INPUT -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN"
fi
# --- PERUBAHAN KRUSIAL 3: HUBUNGKAN JUGA KE FORWARD CHAIN ---
# Ini penting jika server bertindak sebagai gateway.
if ! sudo iptables -C FORWARD -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN" &> /dev/null; then
echo "Menghubungkan chain ke FORWARD untuk port $PROTECTED_PORT"
sudo iptables -I FORWARD -p udp --dport "$PROTECTED_PORT" -j "$IPTABLES_CHAIN"
fi
# Jalankan cleanup di latar belakang
while true; do
cleanup
sleep 300 # Jalankan pembersihan setiap 5 menit
done &
CLEANUP_PID=$!
trap 'kill $CLEANUP_PID; exit' SIGTERM SIGINT
# Memori awal
echo "Penjaga sedang mengingat koneksi dalam $MEMORY_MINUTES menit terakhir..."
sudo journalctl -u udp-custom.service --since "$MEMORY_MINUTES minutes ago" --no-pager | 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"'"
}
}'
awk -i inplace '!seen[$0]++' "$STATE_FILE"
echo "Memori awal selesai. Penjaga siap bertugas!"
# Loop utama pemantauan
echo "Memantau log untuk koneksi ke port $PROTECTED_PORT"
sudo journalctl -u udp-custom.service -f --no-tail | 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 terdeteksi: User '$USER' dari IP '$IP'"
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' mencoba multi-login dari IP '$IP'."
echo "[$(date)] >>> IP lama '$LAST_IP' akan diputuskan dalam 2 menit."
OLD_LAST_SEEN=$(echo "$LAST_ENTRY" | cut -d':' -f3)
sed -i "/^${USER}:${LAST_IP}:/d" "$STATE_FILE"
echo "${USER}:${LAST_IP}:${OLD_LAST_SEEN}:$(date +%s)" >> "$STATE_FILE"
fi
echo "${USER}:${IP}:$(date +%s)::" >> "$STATE_FILE"
awk -i inplace '!seen[$0]++' "$STATE_FILE"
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' telah disconnect. Membersihkan state..."
# --- PERUBAHAN KRUSIAL 4: Hancurkan sesi saat disconnect juga ---
echo "[$(date)] [DEBUG] Disconnect. Menjalankan: sudo conntrack -D -s $ip -p udp"
sudo conntrack -D -s "$ip" -p udp 2>/dev/null
sed -i "/^${USER}:${IP}:/d" "$STATE_FILE"
fi
fi
done
# =================================================================
# --- MEMORI AWAL SAAT STARTUP ---
# =================================================================
echo "Penjaga sedang mengingat koneksi dalam $MEMORY_MINUTES menit terakhir..."
sudo journalctl -u udp-custom.service --since "$MEMORY_MINUTES minutes ago" --no-pager | 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"'"
}
}'
awk -i inplace '!seen[$0]++' "$STATE_FILE"
echo "Memori awal selesai. Penjaga siap bertugas!"
# =================================================================
# --- LOOP UTAMA PEMANTAUAN REAL-TIME ---
# =================================================================
echo "Memantau log untuk koneksi ke port $PROTECTED_PORT"
sudo journalctl -u udp-custom.service -f --no-tail | 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 terdeteksi: User '$USER' dari IP '$IP'"
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' mencoba multi-login dari IP '$IP'."
echo "[$(date)] >>> IP lama '$LAST_IP' akan ditendang dalam 2 menit."
# Tandai IP lama dengan timer
OLD_LAST_SEEN=$(echo "$LAST_ENTRY" | cut -d':' -f3)
sed -i "/^${USER}:${LAST_IP}:/d" "$STATE_FILE"
echo "${USER}:${LAST_IP}:${OLD_LAST_SEEN}:$(date +%s)" >> "$STATE_FILE"
fi
# Tambahkan atau perbarui koneksi baru
echo "${USER}:${IP}:$(date +%s)::" >> "$STATE_FILE"
awk -i inplace '!seen[$0]++' "$STATE_FILE"
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' telah disconnect. Membersihkan state..."
# Hapus entri untuk user dan IP ini, yang membatalkan timer
sed -i "/^${USER}:${IP}:/d" "$STATE_FILE"
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 Connection Enforcer Service
After=network.target udp-custom.service
Wants=udp-custom.service
[Service]
Type=simple
ExecStart=/opt/udp-proxy/bin/enforcer_service.sh
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
3.Simpan dan keluar (Ctrl+X, Y, Enter).
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





