轉載Linux下使用 ipset 封大量IP及ipset參數說明
Linux使用iptables封IP,是常用的應對網絡攻擊的方法,但要封禁成千上萬個IP,如果添加成千上萬條規則,對機器性能影響較大,使用ipset能解決這個問題。
iptables 包含幾個表,每個表由鏈組成。默認的是 filter 表,最常用的也是 filter 表,另一個比較常用的是nat表,封IP就是在 filter 表的 INPUT 鏈添加規則。
在進行規則匹配時,是從規則列表中從頭到尾一條一條進行匹配。
這像是在鏈表中搜索指定節點費力。ipset 提供了把這個 O(n) 的操作變成 O(1) 的方法:就是把要處理的 IP 放進一個集合,對這個集合設置一條 iptables 規則。像 iptable 一樣,IP sets 是 Linux 內核中的東西,ipset 這個命令是對它進行操作的一個工具。
簡單的流程
可以用這幾條命令概括使用 ipset 和 iptables 進行 IP 封禁的流程
ipset create vader hash:ip
iptables -I INPUT -m set --match-set vader src -j DROP
ipset add vader 4.5.6.7
ipset add vader 1.2.3.4
ipset add vader ...
ipset list vader # 查看 vader 集合的內容
下面分別對各條命令進行描述。
創建一個集合
ipset create vader hash:ip
這條命令創建了名為 vader 的集合,以 hash 方式存儲,存儲內容是 IP 地址。
添加 iptables 規則
iptables -I INPUT -m set --match-set vader src -j DROP
如果源地址(src)屬於 vader 這個集合,就進行 DROP 操作。這條命令中,vader 是作為黑名單的,如果要把某個集合作為白名單,添加一個 ‘!’ 符號就可以。
iptables -I INPUT -m set ! --match-set yoda src -j DROP
到現在雖然創建了集合,添加了過濾規則,但是現在集合還是空的,需要往集合里加內容。
找出“壞” IP
找出要封禁的 IP,這是封禁過程中重要的步驟,不過不是這里的重點。簡要說明一下兩種方法思路。
netstat -ntu | tail -n +3 | awk '{print $5}' | sort | uniq -c | sort -nr
直接通過 netstat 的信息,把與本地相關的各種狀態的 IP 都計數,排序列出來。
或者從 nginx 或者其他 web server 的日志里找請求數太多的 IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr
后半部分,排序,去重,再按次數進行逆向排序的操作,跟上面命令是一樣的。
找出“壞” IP,往之前創建的集合里添加就可以了。
ipset add vader 4.5.6.7
有多少“壞” IP,就添加多少 IP,因為針對這些封禁的 IP 只需要一條 iptables 規則,而這些 IP 是以 hash 方式存儲,所以封禁大量的 IP 也不會影響性能,這也是 ipset 存在的最大目的。
You shall not pass!
ipset 更多的用法
存儲類型
前面例子中的 vader 這個集合是以 hash 方式存儲 IP 地址,也就是以 IP 地址為 hash 的鍵。除了 IP 地址,還可以是網絡段,端口號(支持指定 TCP/UDP 協議),mac 地址,網絡接口名稱,或者上述各種類型的組合。
比如指定 hash:ip,port就是 IP 地址和端口號共同作為 hash 的鍵。查看 ipset 的幫助文檔可以看到它支持的所有類型。
下面以兩個例子說明。
HASH:NET
ipset create r2d2 hash:net
ipset add r2d2 1.2.3.0/24
ipset add r2d2 1.2.3.0/30 nomatch
ipset add r2d2 6.7.8.9
ipset test r2d2 1.2.3.2
hash:net 指定了可以往 r2d2 這個集合里添加 IP 段或 IP 地址。
第三條命令里的 nomatch 的作用簡單來說是把 1.2.3.0/30 從 1.2.3.0/24 這一范圍相對更大的段里“剝離”了出來,也就是說執行完 ipset add r2d2 1.2.3.0/24 只后1.2.3.0/24 這一段 IP 是屬於 r2d2 集合的,執行了 ipset add r2d2 1.2.3.0/30 nomatch 之后,1.2.3.0/24 里 1.2.3.0/30 這部分,就不屬於 r2d2 集合了。執行 ipset test r2d2 1.2.3.2 就會得到結果 1.2.3.2 is NOT in set r2d2.
HASH:IP,PORT
ipset create c-3po hash:ip,port
ipset add c-3po 3.4.5.6,80
ipset add c-3po 5.6.7.8,udp:53
ipset add c-3po 1.2.3.4,80-86
第二條命令添加的是 IP 地址為 3.4.5.6,端口號是 80 的項。沒有注明協議,默認就是 TCP,下面一條命令則是指明了是 UDP 的 53 端口。最后一條命令指明了一個 IP 地址和一個端口號范圍,這也是合法的命令。
自動過期,解封
ipset 支持 timeout 參數,這就意味着,如果一個集合是作為黑名單使用,通過 timeout 參數,就可以到期自動從黑名單里刪除內容。
ipset create obiwan hash:ip timeout 300
ipset add obiwan 1.2.3.4
ipset add obiwan 6.6.6.6 timeout 60
上面第一條命令創建了名為 obiwan 的集合,后面多加了 timeout 參數,值為 300,往集合里添加條目的默認 timeout 時間就是 300。第三條命令在向集合添加 IP 時指定了一個不同於默認值的 timeout 值 60,那么這一條就會在 60 秒后自動刪除。
隔幾秒執行一次 ipset list obiwan 可以看到這個集合里條目的 timeout 一直在隨着時間變化,標志着它們在多少秒之后會被刪除。
如果要重新為某個條目指定 timeout 參數,要使用 -exit 這一選項。
ipset -exist add obiwan 1.2.3.4 timeout 100
這樣 1.2.3.4 這一條數據的 timeout 值就變成了 100,如果這里設置 300,那么它的 timeout,也就是存活時間又重新變成 300。
如果在創建集合是沒有指定 timeout,那么之后添加條目也就不支持 timeout 參數,執行 add 會收到報錯。想要默認條目不會過期(自動刪除),又需要添加某些條目時加上 timeout 參數,可以在創建集合時指定 timeout 為 0。
ipset create luke hash:ip
ipset add luke 5.5.5.5 timeout 100
得到報錯信息 kernel error received: Unknown error -1
hashsize, maxelem 這兩個參數分別指定了創建集合時初始的 hash 大小,和最大存儲的條目數量。
ipset create yoda hash:ip,port hashsize 4096 maxelem 1000000
ipset add yoda 3.4.5.6,3306
這樣創建了名為 yoda 的集合,初始 hash 大小是 4096,如果滿了,這個 hash 會自動擴容為之前的兩倍。最大能存儲的數量是 100000 個。
如果沒有指定,hashsize 的默認值是 1024,maxelem 的默認值是 65536。
另外幾條常用命令
ipset del yoda x.x.x.x # 從 yoda 集合中刪除內容
ipset list yoda # 查看 yoda 集合內容
ipset list # 查看所有集合的內容
ipset flush yoda # 清空 yoda 集合
ipset flush # 清空所有集合
ipset destroy yoda # 銷毀 yoda 集合
ipset destroy # 銷毀所有集合
ipset save yoda # 輸出 yoda 集合內容到標准輸出
ipset save # 輸出所有集合內容到標准輸出
ipset restore # 根據輸入內容恢復集合內容
還有……
如果創建集合是指定的存儲內容包含 ip, 例如 hash:ip 或 hash:ip,port ,在添加條目時,可以填 IP 段,但是仍然是以單獨一個個 IP 的方式來存。
上面所有的例子都是用 hash 的方式進行存儲,實際上 ipset 還可以以 bitmap 或者 link 方式存儲,用這兩種方式創建的集合大小,是固定的。
ipset參數如下:
命令
這些選項明確地指定了執行的活動。只有一個命令可以在命令行中規定除非其他的命令在下面。對於所有的長版本命令和選項名稱,必須使用足夠大的空間以確保ipset可以把他們和其他的選項區分開。
-N, --創建 集合名稱 類型 類型具體選項
創建一個用集合名稱命名並且指定類型的集合。類型具體選項必須是系統規定的。
-X, --刪除 [集合名稱]
刪除指定的集合,如果沒有指定或者指定all就刪除全部集合。在刪除集合之前,所有基於集合的綁定和默認綁定都會被移除。
如果集合已經被使用,則什么都不做。
-F, --清空 [集合名稱]
刪除指定集合中的所有規則, 如果沒有指定或者指定了all就清空所有的集合。綁定不會受到清空操作的影響。
-E, --重命名 舊集合名 新集合名
重命名集合,新集合名的標識必須是目前不存在。
-W, --交換 源集合名 目的集合名
交換兩個集合的內容,或者說交換兩個集合的名稱。這兩個集合必須是存在的而且是具有相同的類型才能交換。
-L, --列出 [集合名名稱]
列出指定集合的規則和綁定,如果沒有指定或者指定為all就列出所有的集合。-n選項,數字選項可以用來限定名稱查找和生產數字輸出,當-s ,分類選項已經使用,規則將分類排列(如果給出的集合類型支持這個選項)。
-S, --保存 [集合名稱]
保存指定名稱的集合,如果沒有指定或者指定為all,則保持所有集合:指定恢復可以讀取的標准輸出格式。
-R, --復原
復原已保存的會話.已被保存的會話可以是標准輸入提供的。
當產生一個會話文件的時候請注意支持的命令(創建集合,添加元素,綁定)必須遵循嚴格的規范:首先創建集合添加所有屬於它的集合等等,最后你可以列出所有的綁定命令.此外,這是一個復原選項,所以復原的集合必須是不存在的。
-A, --添加 集合名稱 IP
往集合中添加一個ip。
-D, --刪除 集合名稱IP
從集合中刪除一個ip
-T, --測試 集合名稱 IP
測試一個ip是不是在集合中,要是ip在集合中返回0,如果ip不在集合中則返回非0.
-T, --測試 集合名稱 IP 綁定的目的集合
測試ip是否附屬指定集合的綁定點。如果成功返回0,否則返回非0.關鍵字default可以用來測試集合的默認綁定。
-B, --綁定 集合名稱 IP 綁定的目的集合
綁定集合里的ip和目的集合
-U, --解除綁定 集合名稱 IP
刪除集合中指定ip的綁定。
-H, --幫助 [設置類型]
找出指定設置類型的幫助信息。
在-B –U和-T命令,你可以使用默認的:default,去綁定,解除綁定或者測試默認綁定去代替ip.在-U命令中你可以使用默認的:all去刪除綁定集合的所有元素。
其他選項
接下來的選項可以被指定
-b, --binding setname
這個選擇為-B綁定選項指定值。這是一個強制性的命令. 你在-T中可以用來測試綁定。
-s, --分類
分類標准輸出.當監聽集合,規則列表分類的時候。
-n, --數字
數字輸出。當監聽集合,綁定,ip地址和端口好需要輸出的時候使用數字格式. 默認的系統試着去顯示這些信息用主機名,網絡名和服務,這會引起dns查找。
-q, --安靜
禁止在標准輸出和標准錯誤上有認可輸出但是ipset還是會返回可能的錯誤。
