2016-12-29 151 views
3

我寫了一個shell腳本來讀取一個由IP地址組成的文件,然後在iptables的幫助下將它們封鎖。它工作正常,但是當我第二次運行腳本時,它再次寫入規則(重複)。我想要檢查IP是否已經被阻塞,然後忽略阻塞。這裏是腳本:第一次腳本運行後Shell腳本來讀取文件

#!/bin/bash 
ipadds="/home/asad/Downloads/blacklist" 
dropit=$(grep -Ev "^#" $ipadds) 
for i in $dropit; do 
iptables -A INPUT -s $i -j DROP 
iptables -A FORWARD -s $i -j DROP 
done 

輸出:第2次腳本運行後

[email protected]:/home/asad/Downloads# iptables -L 
Chain INPUT (policy ACCEPT) 
target  prot opt source    destination 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
Chain FORWARD (policy ACCEPT) 
target  prot opt source    destination 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
Chain OUTPUT (policy ACCEPT) 
target  prot opt source    destination 

輸出:

[email protected]:/home/asad/Downloads# iptables -L 
Chain INPUT (policy ACCEPT) 
target  prot opt source    destination 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
Chain FORWARD (policy ACCEPT) 
target  prot opt source    destination 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
DROP  all -- 192.168.248.2  anywhere 
DROP  all -- 192.168.232.20  anywhere 
DROP  all -- 192.168.232.5  anywhere 
DROP  all -- 192.168.232.190  anywhere 
Chain OUTPUT (policy ACCEPT) 
target  prot opt source    destination 

如何避免這種重複?任何幫助,請

+2

不要使用'for'用於循環命令的輸出,使用過程中,替代與'while' – Inian

+0

@gniourf_gniourf:意識到這只是它並沒有解決問題。 – Inian

+0

您的預期代碼不適用於此方式。您應該需要一個數組來存儲命令輸出。您當前的語法允許shell執行單詞拆分以將單個空格分隔的行處理爲多個條目 – Inian

回答

1
#!/bin/bash 
ipadds=/home/asad/Downloads/blacklist 
grep -v "^#" $ipadds | while read i; do 
if ! iptables -nL INPUT | grep -Fq "$i" ; then 
    iptables -A INPUT -s "$i" -j DROP 
    iptables -A FORWARD -s "$i" -j DROP 
fi 
done 

或(也許這差別不大給你)

#!/bin/bash 
ipadds=/home/asad/Downloads/blacklist 
while read i; do 
if ! iptables -nL INPUT | grep -Fq "$i" ; then 
    iptables -A INPUT -s "$i" -j DROP 
    iptables -A FORWARD -s "$i" -j DROP 
fi 
done < <(grep -v "^#" $ipadds) 

請注意,不需要在這種情況下grep-E標誌。將-n標誌傳遞給iptables -L以獲得IP而不是主機名是至關重要的;它也提高了性能。我假設你的INPUT和FORWARD鏈保持同步,因此我只檢查其中一個。如果不是這種情況,當然應該檢查兩者。

上述腳本的確切語義是:「不要插入一個新的候選IP,如果它已經在INPUT鏈中的任何地方提及過」,這與「...如果它已經被阻塞」有點不同。基於iptables -C的更有效的解決方案將尋找特定的規則,但不適用於鏈中IP的其他提及。我可以想到哪種方法更可取的情況。

如果你的iptables鏈中有很多IP,掃描整個鏈來檢查候選IP是否已經存在可能效率低下。如果這成爲一個問題,有多種方法可以建立一個外部索引來進行更高效的IP查找,但是整個系統的OTOH會變得更加難以維護,所以我會在沒有外部索引的情況下嘗試一下。

+0

好點!如果你在'$ i'周圍添加雙引號作爲'「$ i」'會更加粗魯 – Inian

+0

@Inian'$ i'是合法的,當且僅當它包含有效的IP地址,即點和數字(在ipv4環境中),並將其放在引號中只會保留非法字符。爲了提高魯棒性,人們應該相應地解析它,並且這將是低效的。我無法想到'$ ip'會失敗並且''$ ip「'成功的情況。 – Dario

+1

引用不會傷害。特別是如果'IFS'包含一個或多個數字。真的,永遠不要做出假設。只需引用每一個擴展。然而,更大的問題是,這些時段將被解釋爲「匹配任何單個字符」。另一個問題是,正則表達式不是錨定的。 –

0

你可以嘗試

#!/bin/bash 

ipadds="/home/asad/Downloads/blacklist" 

while IFS='' read -r 
do 
    # check if the rule already exists - if not add it - and 
    # silently ignore warnings for rules that dont exist 
    if ! iptables -C INPUT -s "$REPLY" -j DROP 2> /dev/null 
    then 
     iptables -A INPUT -s "$REPLY" -j DROP 
    fi 

    if ! iptables -C FORWARD -s "$REPLY" -j DROP 2> /dev/null 
    then 
     iptables -A FORWARD -s "$REPLY" -j DROP 
    fi 
# Please note proper syntax for process substitution 
done < <(grep -Ev "^#" $ipadds) 
+0

非常好的答案(我編輯它,因爲它缺少必要的''' - 標誌)。 – Dario

+0

@Inian它的工作原理,但得到了很多警告: 「iptables v1.6.0:主機/網絡」找不到「。任何方式感謝您的關注。 –