Linux使用iptables封IP,是經常使用的應對網絡攻擊的方法,但要封禁成千上萬個IP,若是添加成千上萬條規則,對機器性能影響較大,使用ipset能解決這個問題。nginx
iptables 包含幾個表,每一個表由鏈組成。默認的是 filter 表,最經常使用的也是 filter 表,另外一個比較經常使用的是nat表,封IP就是在 filter 表的 INPUT 鏈添加規則。
在進行規則匹配時,是從規則列表中從頭至尾一條一條進行匹配。
這像是在鏈表中搜索指定節點費力。ipset 提供了把這個 O(n) 的操做變成 O(1) 的方法:就是把要處理的 IP 放進一個集合,對這個集合設置一條 iptables 規則。像 iptable 同樣,IP sets 是 Linux 內核中的東西,ipset 這個命令是對它進行操做的一個工具。web
簡單的流程
能夠用這幾條命令歸納使用 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,這是封禁過程當中重要的步驟,不過不是這裏的重點。簡要說明一下兩種方法思路。spa
netstat -ntu | tail -n +3 | awk '{print $5}' | sort | uniq -c | sort -nr
直接經過 netstat 的信息,把與本地相關的各類狀態的 IP 都計數,排序列出來。命令行
或者從 nginx 或者其餘 web server 的日誌裏找請求數太多的 IPrest
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仍是會返回可能的錯誤。