3.iptables

RHEL 7 / CentOS 7 : 關閉 Firewalld 及使用 iptables Sam Tang 19 March 2015 Linux No Comments

Redhat 7 將 Firewalld 成為預設的 firewall, 我使用多年 iptables 還是想用 iptables, 以下是轉用 iptables 的方法:

1. 關閉及停止使用 Firewalld:

systemctl mask firewalld

systemctl stop firewalld

1

2

# systemctl mask firewalld

# systemctl stop firewalld

2. 安裝 iptables

yum install iptables-services

1

# yum install iptables-services

3. 啟動及設定開機執行 iptables

systemctl enable iptables

systemctl start iptables

1

2

# systemctl enable iptables

# systemctl start iptables

vi /root/firewall.sh

[root@localhost ~]# cat firewall.sh

#/bin/bash

#===================<< Clear Original Rule>>=================

iptables -t filter -F

iptables -P INPUT DROP

#========<< test by jaher1 prevent port scan >> ===========

iptables -A INPUT -s 192.168.2.250 -j ACCEPT

iptables -A INPUT -s 192.168.17.2 -j ACCEPT

iptables -A INPUT -s 192.168.201.250/24 -j ACCEPT

iptables -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP

iptables -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

#==========end test by jaher1============

iptables -A INPUT -p all -m state --state INVALID -j DROP

iptables -A INPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT

#iptables -A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT

iptables -A INPUT -p udp -m state --state NEW -m multiport --dports 53 -j ACCEPT

iptables -A INPUT -s 163.28.136.0/24 -p tcp --syn -m state --state NEW -m multiport --dports 53 -j ACCEPT

iptables -A INPUT -s 163.32.225.0/24 -p tcp --syn -m state --state NEW -m multiport --dports 53 -j ACCEPT

#iptables -A INPUT -p tcp --destination-port 65300:65400 -j ACCEPT

#iptables -A INPUT -p tcp --syn -m state --state NEW -m multiport --dports 80 -j ACCEPT

開機自動啟動

vi /etc/rc.d/rc.local

/root/firewall.sh

chmod +x /etc/rc.d/rc.local 開機時可以執行

chmod 700 /root/firewall.sh

chattr +i /root/firewall.sh

/root/firewall.sh

chattr -i /root/firewall.sh ##解開鎖定

------------------------------------------------------------------

Iptables

要讓 iptables 工作,它必須在核心被啟動。我將它加入成模組 (iptables 指令會視需要的時候載入它們) 然後重新編譯核心。更多有關如何在核心中啟用 iptables 的資訊,請見 Iptables Tutorial Chapter 2: Preparations。在您將核心編譯完成之後 (或一邊編譯的時候),您必須安裝 iptables 命令。簡單地 emerge iptables 應該就可以了。

現在經由執行 iptables -L 來測試它是否能工作。如果失敗了,則可能有什麼東西 弄錯了,而您可能得重新檢查一下設定檔。

Iptables 是個 Linux 2.4.x 的核心中新的而且大進步的封包過濾系統。它比 Linux 2.2.x 版中的來得成功。最重要的進步就是它可以依照狀態過濾封包。透過狀態封包過濾,它將能追蹤每個已經建立的 TCP 連線。

我們知道所有的 TCP 都是由一連串的封包組成的。每個封包都含有這些資訊:來源位置、 目的位置、以及一個幫助重組資料的流水號。而我們也知道 TCP 是連線導向而 UDP 不是, 對吧?這些就是它儲存的 "狀態"。現在您應該在問自己 "那又怎樣?",別急,我正要接著 說下去。

一個 TCP 連線包含一連串內有來源 IP 位置、目的 IP 位置、編號 (到了目的地之後才知道資料該如何重組,也才知道誰有到誰沒到) 的封包。TCP 是連線導向的通訊協定,剛好跟非連線導向的 UTP 相反。

藉由驗證 TCP 封包表頭,一個狀態封包過濾器可以得知剛接受的封包是不是現有連線的一部份,然後決定要接受還是丟棄這個封包。

怪客可以透過變更 TCP 封包檔頭來晃點非狀態封包過濾器,讓它接受那些本來應該被丟棄的封包。這可以透過更改 TCP 封包檔頭中的 SYN 旗標或其他旗標來達成。若您使用狀態導向封包過濾器,它則能夠判斷出這個封包不是使用中連線的一部份而拋棄它。這也能防止 "機密偵測" 的可能性,因為這些封包不是現有連線的一部份。

Iptables 也提供其他功能,譬如 NAT (Network Address Translation) 以及流量限制。流量限制在防止 DoS (Denial of Service) 攻擊 (例如 SYN flood) 的時候特別有效。

TCP 連線透過三道確認手續來建立連線。當建立 TCP 連線時,用戶端傳送一個設置了 SYN 旗標的封包至伺服器。伺服器端收到這個封包以後,會傳送一個 SYN+ACK 封包回用戶端。用戶端收到 SYN+ACK 封包以後,會再回覆一個 ACK 封包,表示確認連線。

所謂 SYN 攻擊,就是只傳送 SYN 封包 (檔頭只有 SYN 旗標的封包),而不繼續理會下面兩 個建立連線的封包。一個 SYN 封包並不用包含有效的傳送者位置 (IP) 因為它不需要回覆 。所以這個連線會一直開起直到逾時為止。現在,某個攻擊者丟給您一拖拉庫包含無效傳送 者 IP 的 SYN 封包,您的電腦將持續等待永遠等不到的回應。基於您系統的逾時設定,這 個連線會持續 30-60 秒 (也許更久)。直到可以使用的連線數目全部被用完,而您的電腦將 無法跟任何其他機器通訊。

這就是為什麼流量限制好用的原因。它可以使用 -m limit --limit 1/s 來限制單 一來源的 SYN 封包。這將把 SYN 封包限制在一個來源只有一個,以制止大量的 SYN 封包 將資源淹沒掉。

現在!一些實用的東西!

當 iptables 載入您的核心之後,則有五個鉤子可以掛您的規則。它們叫做 INPUT、OUTPUT、FORWARD、PREROUTING 以及 POSTROUTING。這些清單叫做串鍵 (chains) 因為它依照您加入規則的順序檢查封包,而走到某個規則的時候,這個規則決定丟棄這個封包,則這個封包就會直接被丟棄,下面的規則也不會被執行。

您可以將規則加入至五個主要串鍵,或建立您自己的串鍵然後加入至主串鍵中。Iptables 支援以下指令:

首先我們試著擋住所有來到我們機器的 ICMP 封包,熟悉一下 iptables 指令的用法。

原始碼 12.1: 阻擋所有 ICMP 封包

# iptables -A INPUT -p icmp -j DROP

一開始我們指定想要新增的串鍵,接著指定協定,再來是規則。規則可以是 ACCEP、DROP、REJECT、LOG、QUEUE、MASQUERADE。在這個案例裡我們使用 DROP,它將在不回覆用戶端的狀況下丟棄這個封包。

現在試著 ping localhost。您將無法獲得任何回應,因為我們將所有的來到這台電腦的 ICMP 封包都阻擋起來了。它也讓您無法 ping 其他電腦,因為傳送回來的 ICMP 回應封包也會被擋住。現在清乾淨您的串鍵,讓 ICMP 再次工作。

原始碼 12.2: 清空所有規則

# iptables -F

現在我們看看 iptables 中有關狀態的部份。如果我們想要檢查從 eth0 進入的封包狀態,我們可以這樣作:

原始碼 12.3: 允許來自已經建立連線的封包

# iptables -A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT

這將允許所有已經連線或相關於 INPUT 串鍵的封包。而您可以將不存在狀態列表的封包使用以下方法丟棄:iptables -A INPUT -i eth0 -m state --state INVALID -j DROP。這經由載入加強功能來啟動 iptables 的狀態控制部份。如果您想要外界可以連線至您的電腦,您可以使用 --state NEW。Iptables 包含一些不同意圖的模組,這裡列出一部份:

讓我們試著建立一個使用者定義串鍵並將它套用至某個已經存在的傳鍵:

原始碼 12.4: 建立使用者定義串鍵

(建立一個只有一項規則的新串鍵) # iptables -X mychain # iptables -N mychain # iptables -A mychain -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT(預設的政策是所有出去的傳輸都許可,進來的則忽略。) # iptables -P OUTPUT ACCEPT # iptables -P INPUT DROP(將它加入至 INPUT 串鍵) # iptables -A INPUT -j mychain

經由在 INPUT 串鍵套用這個規則,我們得到一個政策:所有出去的傳輸都許可,進來的除非已經建立連線否則忽略。一般來說這是個爛主意。預設的政策應該是丟棄,但是這是個只是個例子。

如果您想要更多文件,請參閱 iptables documentation

讓我們看一些真正的例子。在這個例子裡我的防火牆╱閘道器指示:

    • 只允許 SSH (埠口 22) 連線至防火牆。

    • 內部網路應該有權使用 HTTP、HTTPS 以及 SSH (DNS 應該也被允許)。

    • 包含大量負載的 ICMP 傳輸會被拒絕。當然我們必須允許一些 ICMP 傳輸。

    • 應該能偵測到埠口掃描然後記錄下來。

    • 防止 SYN 攻擊。

    • 其他任何傳輸應該被忽略並記錄。

原始碼 12.5: /etc/init.d/firewall

#!/sbin/runscript IPTABLES=/sbin/iptables IPTABLESSAVE=/sbin/iptables-save IPTABLESRESTORE=/sbin/iptables-restore FIREWALL=/etc/firewall.rules DNS1=212.242.40.3 DNS2=212.242.40.51 #inside IIP=10.0.0.2 IINTERFACE=eth0 LOCAL_NETWORK=10.0.0.0/24 #outside OIP=217.157.156.144 OINTERFACE=eth1 opts="${opts} showstatus panic save restore showoptions rules" depend() { need net } rules() { stop ebegin "Setting internal rules" einfo "Setting default rule to drop" $IPTABLES -P FORWARD DROP $IPTABLES -P INPUT DROP $IPTABLES -P OUTPUT DROP # 預設規則 einfo "Creating states chain" $IPTABLES -N allowed-connection $IPTABLES -F allowed-connection $IPTABLES -A allowed-connection -m state --state ESTABLISHED,RELATED -j ACCEPT $IPTABLES -A allowed-connection -i $IINTERFACE -m limit -j LOG --log-prefix \ "Bad packet from ${IINTERFACE}:" $IPTABLES -A allowed-connection -j DROP # ICMP 傳輸 einfo "Creating icmp chain" $IPTABLES -N icmp_allowed $IPTABLES -F icmp_allowed $IPTABLES -A icmp_allowed -m state --state NEW -p icmp --icmp-type \ time-exceeded -j ACCEPT $IPTABLES -A icmp_allowed -m state --state NEW -p icmp --icmp-type \ destination-unreachable -j ACCEPT $IPTABLES -A icmp_allowed -p icmp -j LOG --log-prefix "Bad ICMP traffic:" $IPTABLES -A icmp_allowed -p icmp -j DROP # 進來的傳輸 einfo "Creating incoming ssh traffic chain" $IPTABLES -N allow-ssh-traffic-in $IPTABLES -F allow-ssh-traffic-in #Flood protection $IPTABLES -A allow-ssh-traffic-in -m limit --limit 1/second -p tcp --tcp-flags \ ALL RST --dport ssh -j ACCEPT $IPTABLES -A allow-ssh-traffic-in -m limit --limit 1/second -p tcp --tcp-flags \ ALL FIN --dport ssh -j ACCEPT $IPTABLES -A allow-ssh-traffic-in -m limit --limit 1/second -p tcp --tcp-flags \ ALL SYN --dport ssh -j ACCEPT $IPTABLES -A allow-ssh-traffic-in -m state --state RELATED,ESTABLISHED -p tcp --dport ssh -j ACCEPT # 出去的傳輸 einfo "Creating outgoing ssh traffic chain" $IPTABLES -N allow-ssh-traffic-out $IPTABLES -F allow-ssh-traffic-out $IPTABLES -A allow-ssh-traffic-out -p tcp --dport ssh -j ACCEPT einfo "Creating outgoing dns traffic chain" $IPTABLES -N allow-dns-traffic-out $IPTABLES -F allow-dns-traffic-out $IPTABLES -A allow-dns-traffic-out -p udp -d $DNS1 --dport domain \ -j ACCEPT $IPTABLES -A allow-dns-traffic-out -p udp -d $DNS2 --dport domain \ -j ACCEPT einfo "Creating outgoing http/https traffic chain" $IPTABLES -N allow-www-traffic-out $IPTABLES -F allow-www-traffic-out $IPTABLES -A allow-www-traffic-out -p tcp --dport www -j ACCEPT $IPTABLES -A allow-www-traffic-out -p tcp --dport https -j ACCEPT # 偵測掃描埠口的傢伙 einfo "Creating portscan detection chain" $IPTABLES -N check-flags $IPTABLES -F check-flags $IPTABLES -A check-flags -p tcp --tcp-flags ALL FIN,URG,PSH -m limit \ --limit 5/minute -j LOG --log-level alert --log-prefix "NMAP-XMAS:" $IPTABLES -A check-flags -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP $IPTABLES -A check-flags -p tcp --tcp-flags ALL ALL -m limit --limit \ 5/minute -j LOG --log-level 1 --log-prefix "XMAS:" $IPTABLES -A check-flags -p tcp --tcp-flags ALL ALL -j DROP $IPTABLES -A check-flags -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG \ -m limit --limit 5/minute -j LOG --log-level 1 --log-prefix "XMAS-PSH:" $IPTABLES -A check-flags -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP $IPTABLES -A check-flags -p tcp --tcp-flags ALL NONE -m limit \ --limit 5/minute -j LOG --log-level 1 --log-prefix "NULL_SCAN:" $IPTABLES -A check-flags -p tcp --tcp-flags ALL NONE -j DROP $IPTABLES -A check-flags -p tcp --tcp-flags SYN,RST SYN,RST -m limit \ --limit 5/minute -j LOG --log-level 5 --log-prefix "SYN/RST:" $IPTABLES -A check-flags -p tcp --tcp-flags SYN,RST SYN,RST -j DROP $IPTABLES -A check-flags -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit \ --limit 5/minute -j LOG --log-level 5 --log-prefix "SYN/FIN:" $IPTABLES -A check-flags -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP # 在串鍵套用以及增加無效的狀態 einfo "Applying chains to INPUT" $IPTABLES -A INPUT -m state --state INVALID -j DROP $IPTABLES -A INPUT -j icmp_allowed $IPTABLES -A INPUT -j check-flags $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A INPUT -j allow-ssh-traffic-in $IPTABLES -A INPUT -j allowed-connection einfo "Applying chains to FORWARD" $IPTABLES -A FORWARD -m state --state INVALID -j DROP $IPTABLES -A FORWARD -j icmp_allowed $IPTABLES -A FORWARD -j check-flags $IPTABLES -A FORWARD -o lo -j ACCEPT $IPTABLES -A FORWARD -j allow-ssh-traffic-in $IPTABLES -A FORWARD -j allow-www-traffic-out $IPTABLES -A FORWARD -j allowed-connection einfo "Applying chains to OUTPUT" $IPTABLES -A OUTPUT -m state --state INVALID -j DROP $IPTABLES -A OUTPUT -j icmp_allowed $IPTABLES -A OUTPUT -j check-flags $IPTABLES -A OUTPUT -o lo -j ACCEPT $IPTABLES -A OUTPUT -j allow-ssh-traffic-out $IPTABLES -A OUTPUT -j allow-dns-traffic-out $IPTABLES -A OUTPUT -j allow-www-traffic-out $IPTABLES -A OUTPUT -j allowed-connection # 允許用戶端可以透過 NAT (Network Address Translation - 網路位置轉譯) 路由 $IPTABLES -t nat -A POSTROUTING -o $IINTERFACE -j MASQUERADE eend $? } start() { ebegin "Starting firewall" if [ -e "${FIREWALL}" ]; then restore else einfo "${FIREWALL} does not exists. Using default rules." rules fi eend $? } stop() { ebegin "Stopping firewall" $IPTABLES -F $IPTABLES -t nat -F $IPTABLES -X $IPTABLES -P FORWARD ACCEPT $IPTABLES -P INPUT ACCEPT $IPTABLES -P OUTPUT ACCEPT eend $? } showstatus() { ebegin "Status" $IPTABLES -L -n -v --line-numbers einfo "NAT status" $IPTABLES -L -n -v --line-numbers -t nat eend $? } panic() { ebegin "Setting panic rules" $IPTABLES -F $IPTABLES -X $IPTABLES -t nat -F $IPTABLES -P FORWARD DROP $IPTABLES -P INPUT DROP $IPTABLES -P OUTPUT DROP $IPTABLES -A INPUT -i lo -j ACCEPT $IPTABLES -A OUTPUT -o lo -j ACCEPT eend $? } save() { ebegin "Saving Firewall rules" $IPTABLESSAVE > $FIREWALL eend $? } restore() { ebegin "Restoring Firewall rules" $IPTABLESRESTORE < $FIREWALL eend $? } restart() { svc_stop; svc_start } showoptions() { echo "Usage: $0 {start|save|restore|panic|stop|restart|showstatus}" echo "start) will restore setting if exists else force rules" echo "stop) delete all rules and set all to accept" echo "rules) force settings of new rules" echo "save) will store settings in ${FIREWALL}" echo "restore) will restore settings from ${FIREWALL}" echo "showstatus) Shows the status" }

一些建立防火牆的忠告:

    1. 在實際建立防火牆之前先擬定政策

    2. 盡量讓它簡單

    3. 了解通訊協定到底怎麼工作 (閱讀 RFC (Request For Comments))

    4. 永遠記得,防火牆只是另外一個以根 (root) 使用者執行的程式。

    5. 測試您的防火牆