Skip to content

Instantly share code, notes, and snippets.

@ishworgurung
Created February 19, 2026 13:14
Show Gist options
  • Select an option

  • Save ishworgurung/5d75f308be86c26b7406cb48612670f4 to your computer and use it in GitHub Desktop.

Select an option

Save ishworgurung/5d75f308be86c26b7406cb48612670f4 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euf -o pipefail
# Block countries by IP range using ipset + iptables
# Zone files from ipdeny.com, cached locally for reliability
#
# Usage: ./drop.bash [--update]
# --update Re-download zone files before applying rules
# Install: ipset, iptables-persistent on Ubuntu
ZONE_DIR="/etc/ipset-countries/zones"
ZONE_URL="http://www.ipdeny.com/ipblocks/data/countries"
# Countries to block: code=name
declare -A COUNTRIES=(
[ru]="Russia"
[cn]="China"
[br]="Brazil"
[ro]="Romania"
[pk]="Pakistan"
[ua]="Ukraine"
[ir]="Iran"
[kp]="North Korea"
)
mkdir -p "$ZONE_DIR"
# Download zone files only when explicitly asked
if [[ "$1" == "--update" ]]; then
echo "Downloading zone files..."
for code in "${!COUNTRIES[@]}"; do
echo " ${COUNTRIES[$code]} ($code)"
wget -q -O "$ZONE_DIR/$code.zone" "$ZONE_URL/$code.zone"
done
echo "Zone files updated."
fi
# Apply rules for each country
for code in "${!COUNTRIES[@]}"; do
SETNAME="${code}_zone"
ZONEFILE="$ZONE_DIR/$code.zone"
if [[ ! -f "$ZONEFILE" ]]; then
echo "SKIP: $ZONEFILE not found for ${COUNTRIES[$code]} — run with --update first"
continue
fi
echo "Blocking ${COUNTRIES[$code]} ($code)..."
# Create or flush the ipset
ipset list "$SETNAME" &>/dev/null && ipset flush "$SETNAME" || ipset create "$SETNAME" hash:net
# Load IPs
COUNT=0
while IFS= read -r IP; do
[[ -z "$IP" || "$IP" == \#* ]] && continue
ipset add "$SETNAME" "$IP" 2>/dev/null
((COUNT++))
done < "$ZONEFILE"
echo " Loaded $COUNT ranges into $SETNAME"
# Add iptables rule if not already present (all protocols)
if ! iptables -C INPUT -m set --match-set "$SETNAME" src -j DROP 2>/dev/null; then
iptables -A INPUT -m set --match-set "$SETNAME" src -j DROP
fi
if ! iptables -C OUTPUT -m set --match-set "$SETNAME" dst -j DROP 2>/dev/null; then
iptables -A OUTPUT -m set --match-set "$SETNAME" dst -j DROP
fi
done
echo ""
echo "Done. Blocked countries: ${COUNTRIES[*]}"
echo "Run 'iptables -L INPUT -n | grep zone' to verify."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment