什麼是 ipset#
ipset 是 Linux 上一個用來高效管理 IP 地址集合的工具。你可以把它想像成一個 IP 地址的 “容器” 或者 “列表”,但這個 “列表” 的查找速度非常快,特別適合用在防火牆規則中。
ipset 在這裡的作用就是管理 IP 地址集合。
開始之前#
以下以中國大陸伺服器阻斷海外 IP 為例 - Ubuntu 24.04 LTS (Noble Numbat)
確保擁有其他非網路途徑可以訪問伺服器,以便恢復錯誤的 iptables 規則,比如 VNC 等
首先,我們需要擁有一個指定區域的 IP 集合,可以通過如下命令進行獲取:
# *也可以更換為其他的更全面的IP集合
# 下載中國IP地址集合
wget -P . http://www.ipdeny.com/ipblocks/data/countries/cn.zone
其次,安裝 ipset
sudo apt install ipset -y
最後,創建集合
# 創建一個名為cnip的集合
ipset -N cnip hash:net
# 導入剛剛下載的IP集合的IP到cnip集合中
for i in $(cat ./cn.zone ); do ipset -A cnip $i; done
開始阻斷#
為確保規則生效,需要清鏈,請勿直接在生產環境進行操作,注意備份
# 備份原有規則
iptables-save > ~/iptables.bak
# 清鏈
iptables -F
iptables -X
# 允許本地回環
iptables -A INPUT -i lo -j ACCEPT
# 阻斷所有海外IP(不符合cnip集合的IP)(僅允許中國IP(cnip集合內的IP)訪問)
iptables -A INPUT -m set ! --match-set cnip src -j DROP
# 或者不允許中國IP訪問,可以把感嘆號“! ”去掉即可
注意#
首先,注意備份原有規則,防止出現問題。
其次,需要經常或者定期更新 IP 地址庫。
再其次,Docker 等特殊鏈需要自行思考處理方式。
最後,伺服器重啟會導致規則丟失,可以編寫個腳本去開機自動執行 iptabes 規則。
更新 2025-02-12#
今天又嘗試了一下 Docker 屏蔽海外的 IP(緊接上文)
如果容器是主機網路模式(Host)則會與宿主機一致,無需單獨更改,一下情況只針對橋模式(Bridge)
首先我們需要明白,Docker 橋流量在什麼鏈之後會被地址轉換(此處特指 SNAT,源地址轉換),SNAT 過的地址是判斷不了是否來自於海外,而 SNAT 發生的地方就是 FORWARD 鏈的後一個鏈,即 POSTROUTING 鏈(PREROUTING→FORWARD→POSTROUTING)
補充:DNAT(目的地址轉換)是發生在 FORWARD 鏈的前一個鏈,即 PREROUTING 鏈
理論存在,實踐開始
我們只需要判斷源地址,所以我們只需要在 FORWARD 鏈上面做一些手腳。
首先,我們把原有的 iptables 規則備份:iptables-save > ~/iptables.bak
然後,複製出來一個新的規則(名為 iptables-only-allow-cnip-docker),並將原有的 2 個規則註釋掉:
# 含義是將轉發的流量直接交給DOCKER的鏈
# -A FORWARD -j DOCKER-USER
# -A FORWARD -j DOCKER-ISOLATION-STAGE-1
註釋完成之後,將如下規則填入到註釋掉的 2 個規則的下面
iptables 的規則是按順序執行的
# 含義是將來自於eth0網卡且匹配cnip的IP集合的流量交給DOCKER相關的鏈(僅允許來自於cnip的IP)
# 注:eth0為我的本機網卡,如有別的網卡,自行添加或者更改
-A FORWARD -i eth0 -m set --match-set cnip src -j DOCKER-USER
-A FORWARD -i eth0 -m set --match-set cnip src -j DOCKER-ISOLATION-STAGE-1
# 丟棄eth0網卡上不匹配cnip的IP集合流量的封包(阻斷來自於非cnip的IP)
# 注:eth0為我的本機網卡,如有別的網卡,自行添加或者更改
-A FORWARD -i eth0 -m set ! --match-set cnip src -j DROP
修改完成之後,將規則導入至 iptables 使其生效
iptables-restore < ~/iptables-only-allow-cnip-docker
效果#
- Docker 橋網路
- 本機網路