iptables 是運作在使用者空間的應用軟體,通過控制 Linux 核心 netfilter 子產品,來管理網絡資料包的處理和轉發。在大部分 Linux 發行版中,可以通過手冊頁 或 man iptables 擷取使用者手冊。通常 iptables 需要核心子產品支援才能運作,此處相應的核心子產品通常是 Xtables。
Linux安全之iptables自定義鍊
【1】自定義鍊的原因
【2】使用者自定義鍊的設計
【3】使用者自定義鍊建立
【4】使用者自定義鍊重命名
【5】使用者自定義鍊删除
【6】實戰示範
Linux安全之iptables自定義鍊
- 【1】自定義鍊的原因
之前,我們一直在使用的都是 iptables 預設鍊中定義規則,所有我們也可以自定義鍊。
當預設鍊中的規則非常多時,不友善我們管理。
想象一下,如果 INPUT鍊中存放了 200 條規則,這 200 條規則有針對 httpd 服務的,有針對 sshd 服務的,有針對私網 IP 的,有針對公網 IP 的。假如,我們突然想要修改針對 httpd 服務的相關規則,難道我們還要從頭看一遍這 200 條規則,找出哪些規則是針對 httpd 的嗎?這顯然不合理。
是以,iptables 中可以自定義鍊,通過自定義鍊即可解決上述問題。
- 【2】使用者自定義鍊的設計
假設,我們自定義一條鍊,鍊名叫 IN_WEB。我們可以将所有針對 80 端口的入站規則都寫入到這條自定義鍊中,當以後想要修改針對 Web 服務的入站規則時,就直接修改 IN_WEB 鍊中的規則就好了。即使預設鍊中有再多的規則,我們也不會害怕了,因為我們知道,所有針對 80 端口的入站規則都存放在 IN_WEB 鍊中。
同理,我們可以将針對 sshd 的出站規則放入到 OUT_SSH 自定義鍊中,将針對 Nginx 的入站規則放入到 IN_NGINX 自定義鍊中,這樣,我們就能想改哪裡改哪裡,再也不同擔心找不到規則在哪裡了。
但是需要注意的是,自定義鍊并不能直接使用,而是需要被預設鍊引用才能夠使用。
- 【3】使用者自定義鍊建立
# 清空防火牆
$ sudo iptables -t filter -F
# 建立一個自定義鍊為IN_WEB
$ sudo iptables -t filter -N IN_WEB
# 可以看到自定義的IN_WEB鍊
$ sudo iptables -t filter -nvL
Chain IN_WEB (0 references)
pkts bytes target prot opt in out source destination
......
自定義鍊建立完成後,檢視 filter 表中的鍊。發現自定義鍊已經被建立,而且這條自定義鍊的引用計數為 0 (0 references),也就是說,這條自定義鍊還沒有被任何預設鍊所引用。是以,即使 IN_WEB 中配置了規則,也不會生效。
自定義鍊已經建立完畢,現在我們就可以直接在自定義鍊中配置規則了。
# 對自定義鍊的操作與對預設鍊的操作基本一緻
$ sudo iptables -I IN_WEB -s 192.168.31.139 -j REJECT
$ sudo iptables -t filter -I IN_WEB -s 192.168.31.140 -j REJECT
# 兩者操作基本一緻
$ sudo iptables -t filter -nvL
Chain IN_WEB (0 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.31.140 0.0.0.0/0 reject-with icmp-port-unreachable
0 0 REJECT all -- * * 192.168.31.139 0.0.0.0/0 reject-with icmp-port-unreachable
......
自定義鍊中已經有了一些規則,但是現在這些規則無法比對到任何封包,因為我們并沒有在任何預設鍊中引用它。既然 IN_WEB 鍊是為了針對 Web 服務的入站規則而建立的,那麼這些規則應該去比對入站的封包,是以我們應該用 INPUT 鍊去引用它。
當然,自定義鍊在哪裡建立,應該被哪條預設鍊引用,取決于實際的工作場景,因為此處示例的規則是比對入站封包,是以在 INPUT 鍊中引用自定義鍊。
# 定義引用規則,使用-j指定自定義鍊
# 在INPUT鍊中添加了一條規則,通路本機80端口的tcp封包将會被這條規則比對到IN_WEB鍊
$ sudo iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB
# 檢視定義的引用規則
$ sudo iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 IN_WEB tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain IN_WEB (1 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.31.140 0.0.0.0/0 reject-with icmp-port-unreachable
0 0 REJECT all -- * * 192.168.31.139 0.0.0.0/0 reject-with icmp-port-unreachable
......
我們使用 -j 選項指定動作,而此處,我們将動作替換為了自定義鍊。當 -j 對應的值為一個自定義鍊時,就表示被目前規則比對到的封包将交由對應的自定義鍊處理,具體怎樣處理取決于自定義鍊中的規則。
當 IN_WEB 自定義鍊被 INPUT 鍊引用以後,可以發現,IN_WEB 鍊的引用計數已經變為 1,表示這條自定義鍊已經被引用了 1 次,自定義鍊還可以引用其他的自定義鍊。
那麼此刻,我們在 192.168.31.140 上嘗試通路本機的 80 端口,已經被拒絕通路,證明剛才自定義鍊中的規則已經生效了。
- 【4】使用者自定義鍊重命名
過了一段時間,我們發現 IN_WEB 這個名字不太合适,我們想要将這條自定義鍊重命名,把名字改成 WEB。
# 自定義鍊重命名
$ sudo iptables -t filter -E IN_WEB WEB
# 檢視定義的引用規則
$ sudo iptables -t filter -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 WEB tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain WEB (1 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.31.140 0.0.0.0/0 reject-with icmp-port-unreachable
0 0 REJECT all -- * * 192.168.31.139 0.0.0.0/0 reject-with icmp-port-unreachable
- 【5】使用者自定義鍊删除
好了,我們已經能夠建立自定義了,那麼怎樣删除自定義鍊呢?可以使用 iptables 的 -X 選項可以删除自定義鍊。
但是删除自定義鍊時,需要滿足兩個條件:
- 1、自定義鍊沒有被任何預設鍊引用,即自定義鍊的引用計數為 0。
- 2、自定義鍊中沒有任何規則,即自定義鍊為空。
# (1) 删除引用自定義鍊的規則
$ sudo iptables -t filter -D INPUT 1
# (2) 需要清空對應的自定義鍊
$ sudo iptables -t filter -F WEB
# (3) 删除自定義鍊
$ sudo iptables -t filter -X WEB
- 【6】實戰示範
# 清空nat鍊的規則
$ sudo iptables -t nat -F
# 建立自定義鍊
$ sudo iptables -N clean_in
# 限制icmp協定的廣播ping
$ sudo iptables -A clean_in -d 255.255.255.255 -p icmp -j DROP
$ sudo iptables -A clean_in -d 172.16.255.255 -p icmp -j DROP
# 禁止非法包
$ sudo iptables -A clean_in -p tcp ! --syn -m state --state NEW -j DROP
$ sudo iptables -A clean_in -p tcp --tcp-flags ALL ALL -j DROP
$ sudo iptables -A clean_in -p tcp --tcp-flags ALL NONE -j DROP
#(1)如果是外網通路本地位址172.16.100.7則交給自定義鍊clean_in處理
$ sudo iptables -A INPUT -d 172.16.100.7 -j clean_in
#(2)如果自定義鍊沒有一條比對上,則return回去;自定義鍊傳回
$ sudo iptables -A clean_in -d 172.16.100.7 -j RETURN
#(3)本地回環接口都允許
$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A OUTPUT -o lo -j ACCEPT
#(4)禁止端口
$ sudo iptables -A INPUT -i eth0 -m multiport -p tcp --dports 53,113,135,137,139,445 -j DROP
$ sudo iptables -A INPUT -i eth0 -m multiport -p udp --dports 53,113,135,137,139,445 -j DROP
$ sudo iptables -A INPUT -i eth0 -p udp --dport 1026 -j DROP
$ sudo iptables -A INPUT -i eth0 -m multiport -p tcp --dports 1433,4899 -j DROP
# icmp速率限制
$ sudo iptables -A INPUT -p icmp -m limit --limit 10/second -j ACCEPT