Το ipset σου επιτρέπει να φτιάξεις μια λίστα (set) από IPs και να εφαρμόσεις έναν κανόνα firewall πάνω σε αυτήν. Έτσι μπορείς εύκολα να φορτώσεις blocklists χιλιάδων IPs χωρίς να γεμίσεις το firewal (UFW) με κανόνες.
Βήματα
Εγκατέστησε το ipset:
sudo apt update
sudo apt install ipset iptables curl
Δημιούργησε μια λίστα (π.χ. banlist):
sudo ipset create banlist hash:ip
Πρόσθεσε IPs στη λίστα:
sudo ipset add banlist 1.2.3.4
sudo ipset add banlist 5.6.7.8
Αν έχεις αρχείο με IPs:
while read ip; do sudo ipset add banlist $ip; done < banlist.txt
Σύνδεσε τη λίστα με το UFW (στην πραγματικότητα μέσω iptables που χρησιμοποιεί το UFW):
sudo iptables -I INPUT -m set --match-set banlist src -j DROP
(Αυτό θα ρίχνει όλα τα πακέτα από IPs που είναι στη λίστα).
Αν θες να το κάνεις μόνιμο στο boot:
Βάζεις τους κανόνες στο /etc/ufw/before.rules
Ή χρησιμοποιείς systemd unit/script που επαναφορτώνει τη λίστα και τον κανόνα στο startup.
Παρακάτω θα βρεις έτοιμη υλοποίηση για Debian/Ubuntu που:
- Κατεβάζει μία ή περισσότερες blocklists,
- Τις φορτώνει σε ipset (IPv4 & IPv6),
- Εφαρμόζει κανόνα DROP μέσω iptables/ip6tables (παίζει κανονικά με UFW),
- Τις ενημερώνει αυτόματα με systemd timer,
- Επιβιώνει από reboot χωρίς να πειράξουμε αρχεία του UFW.
1)Εγκατάσταση πακέτων
sudo apt update
sudo apt install -y ipset iptables
2) Αρχείο πηγών (λίστες) – μπορείς να το προσαρμόσεις
sudo mkdir -p /etc/ipset
sudo tee /etc/ipset/banlist.sources >/dev/null <<'EOF'
# One URL per line. Lines starting with # are ignored.
# You can add or remove URLs as you like.
# Example sources (FireHOL level1 + blocklist.de all):
https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset
https://lists.blocklist.de/lists/all.txt
EOF3) Script ενημέρωσης & φόρτωσης ipset Κανουμε edit το παρακάτω αρχείο
nano /usr/local/bin/update-banlists.sh
και προσθέτουμε τον κώδικα
#!/usr/bin/env bash
set -euo pipefail
# ==============================
# Config (paths)
# ==============================
SOURCES_FILE="/etc/ipset/banlist.sources"
STATE_DIR="/var/lib/ipset"
TMP_DIR="$(mktemp -d)"
IPV4_SET="banlist"
IPV6_SET="banlist6"
SAVE_FILE_V4="${STATE_DIR}/${IPV4_SET}.save"
SAVE_FILE_V6="${STATE_DIR}/${IPV6_SET}.save"
# ==============================
# Helpers
# ==============================
log() { echo "[update-banlists] $*"; }
ensure_prereqs() {
command -v ipset >/dev/null || { echo "ipset not found"; exit 1; }
mkdir -p "$STATE_DIR"
}
ensure_sets_exist() {
# Create sets if missing (idempotent)
if ! ipset list -n | grep -qx "$IPV4_SET"; then
ipset create "$IPV4_SET" hash:ip family inet timeout 0
fi
if ! ipset list -n | grep -qx "$IPV6_SET"; then
ipset create "$IPV6_SET" hash:ip family inet6 timeout 0
fi
}
download_sources() {
local line url out="${TMP_DIR}/combined.txt"
: > "$out"
while IFS= read -r line; do
url="$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
[[ -z "$url" ]] && continue
[[ "$url" =~ ^# ]] && continue
log "Downloading $url"
if curl -fsSL "$url" | sed 's/\r$//' >> "$out"; then
:
else
log "WARN: failed to fetch $url"
fi
done < "$SOURCES_FILE"
# Keep only lines that look like IP (v4 or v6) or CIDR
# Many lists already are just IP/CIDR per line.
grep -E -i '^[0-9a-f:.]+(/[0-9]+)?$' "$out" | sed 's/ //g' | sort -u > "${TMP_DIR}/ips.txt"
}
flush_and_reload_sets() {
# We'll rebuild using temporary sets to avoid race conditions
local TMP_V4="${IPV4_SET}_new"
local TMP_V6="${IPV6_SET}_new"
# Create temp sets
ipset create "$TMP_V4" hash:ip family inet || true
ipset create "$TMP_V6" hash:ip family inet6 || true
# Populate temp sets
while IFS= read -r ip; do
[[ -z "$ip" ]] && continue
if [[ "$ip" == *:* ]]; then
# Likely IPv6
ipset add "$TMP_V6" "$ip" 2>/dev/null || true
else
# Likely IPv4
ipset add "$TMP_V4" "$ip" 2>/dev/null || true
fi
done < "${TMP_DIR}/ips.txt"
# Swap
ipset swap "$TMP_V4" "$IPV4_SET"
ipset swap "$TMP_V6" "$IPV6_SET"
# Destroy temp sets
ipset destroy "$TMP_V4" || true
ipset destroy "$TMP_V6" || true
# Save to disk
ipset save "$IPV4_SET" > "$SAVE_FILE_V4"
ipset save "$IPV6_SET" > "$SAVE_FILE_V6"
}
apply_firewall_rules() {
# Ensure iptables rules exist (idempotent)
if ! iptables -C INPUT -m set --match-set "$IPV4_SET" src -j DROP 2>/dev/null; then
iptables -I INPUT -m set --match-set "$IPV4_SET" src -j DROP
fi
if command -v ip6tables >/dev/null; then
if ! ip6tables -C INPUT -m set --match-set "$IPV6_SET" src -j DROP 2>/dev/null; then
ip6tables -I INPUT -m set --match-set "$IPV6_SET" src -j DROP
fi
fi
}
restore_from_disk_if_empty() {
# If sets are empty and we have a saved copy, restore
if [ "$(ipset list "$IPV4_SET" | awk '/Number of entries:/ {print $4}')" = "0" ] 2>/dev/null && [ -s "$SAVE_FILE_V4" ]; then
ipset restore < "$SAVE_FILE_V4" || true
fi
if [ "$(ipset list "$IPV6_SET" | awk '/Number of entries:/ {print $4}')" = "0" ] 2>/dev/null && [ -s "$SAVE_FILE_V6" ]; then
ipset restore < "$SAVE_FILE_V6" || true
fi
}
main() {
ensure_prereqs
ensure_sets_exist
# Make sure firewall rules exist before/after update
apply_firewall_rules
restore_from_disk_if_empty
download_sources
flush_and_reload_sets
apply_firewall_rules
log "Done. Entries:"
ipset list "$IPV4_SET" | awk '/Number of entries:/ {print "IPv4:", $4}'
ipset list "$IPV6_SET" | awk '/Number of entries:/ {print "IPv6:", $4}'
}
trap 'rm -rf "$TMP_DIR"' EXIT
main
Κάνουμε εκτελέσιμο το update-banlists.sh
sudo chmod +x /usr/local/bin/update-banlists.sh
sudo mkdir -p /var/lib/ipset
και δημιουργουμε έναν φάκελο οπου θα μπουν τα 2 αρχεία banlist.save & banlist6.save που εμπεριέχουν τις banαρισμένες IP
sudo mkdir -p /var/lib/ipset
4) Υπηρεσία εκκίνησης (εφαρμογή κανόνων στο boot) Φτιαχνουμε το αρχείο ipset-banlist.service
sudo nano /etc/systemd/system/ipset-banlist.service
και βάζουμε τα παρακάτω.
[Unit]
Description=Create/restore ipset ban lists and enforce firewall rules
After=network-online.target ufw.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-banlists.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Κάνουμε το αρχείο να τρέχει ipset-banlist.service σαν υπηρεσία
sudo systemctl daemon-reload
sudo systemctl enable --now ipset-banlist.service
5) Προγραμματισμένη αυτόματη ενημέρωση (ημερησίως)
Πάμε στο/etc/systemd/system/ipset-banlist-update.service
nano /etc/systemd/system/ipset-banlist-update.service
και επικόλληση το παρακάτω
[Unit]
Description=Update ipset ban lists from remote sources
[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-banlists.sh
Και ορίζουμε και τον χρονοδιακόπτη
nano /etc/systemd/system/ipset-banlist-update.timer
και επικόλληση το παρακάτω
[Unit]
Description=Run ipset ban lists update daily
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=600
[Install]
WantedBy=timers.target
6) Έλεγχος λειτουργίας
Τρέξε χειροκίνητα μία ενημέρωση:
sudo /usr/local/bin/update-banlists.sh
Δες πόσες εγγραφές φορτώθηκαν:
sudo ipset list banlist | awk '/Number of entries:/ {print}'
sudo ipset list banlist6 | awk '/Number of entries:/ {print}'
Επιβεβαίωσε ότι οι κανόνες υπάρχουν:
sudo iptables -S | grep match-set || true
sudo ip6tables -S | grep match-set || true
Έλεγχος των timers:
systemctl list-timers | grep ipset-banlist-update || true
Σημειώσεις / Καλές Πρακτικές
UFW συμβατότητα: Δεν τροποποιούμε τα αρχεία του UFW. Οι κανόνες iptables/ip6tables εφαρμόζονται ξεχωριστά και ισχύουν σε κάθε boot από το ipset-banlist.service. Αν κάνεις ufw reload, το service ή το timer ξανατρέχουν και τους ξανασφαλίζουν.
Πηγές: Μπορείς να προσθέσεις/αφαιρέσεις URLs στο /etc/ipset/banlist.sources. Το script διαβάζει κάθε γραμμή και προσθέτει IPs/CIDRs.
IPv6: Καλύπτεται με ξεχωριστό set (banlist6) και κανόνα ip6tables.
Απαλοιφή: Αν χρειαστεί κάποια IP να επιτραπεί, μπορείς να την αφαιρέσεις από το set:
sudo ipset del banlist 203.0.113.10
* Παρατήρηση: Θα ξαναμπεί στην επόμενη ενημέρωση αν υπάρχει στη λίστα
Tags: Secure Linux Firewall with IPSet Blocklists, Linux IPSet Firewall Automation,Dynamic IP Blocking on Linux with IPSet,Harden your Linux server with IPSet blocklists,Blocking Malicious IPs with IPSet and FireHOL Lists,Linux Security Guide: Banlist via IPSet,firewall με blocklists μέσω ipset σε Debian/Ubuntu.


0 Comments