Linux防火牆之iptables常用擴充套件匹配條件(二)
上一篇博文我們講到了iptables的一些常用的擴充套件匹配模組以及擴充套件模組的一些選項的說明,回顧請參考https://www.cnblogs.com/qiuhom-1874/p/12273755.html;今天再來說說剩下的幾個比較長用的擴充套件模組。
1、limit,此模組主要是基於收發報文段速率來做匹配,通俗的將就是來控制訪問速率的。其原理是用的令牌桶演算法,具體如下圖
提示:從圖上大概可以瞭解到它的基本流程,首先令牌桶在第一次會生成一定數量的令牌,然後使用者要訪問伺服器,需要從令牌桶裡拿令牌才可以訪問,這個令牌桶有個特點,就是如果令牌桶裡的令牌是滿的,它就不會生成新的令牌,如果令牌桶裡的令牌不是滿的,它會以一定速率的向令牌桶裡放令牌,這個放令牌的速度是一個恆定的值,它不取決於令牌用的速度,即便令牌桶空了,它也是一定時間生成一定量的令牌來往裡生成令牌;如果令牌桶裡的令牌沒有了,這時又有新的請求,那麼沒有拿到令牌的請求將會丟棄,不予處理其請求。這樣一種控制速率的機制,它有個特點就是在最開始的請求中,也就是令牌桶是滿的狀態,可能存在短時間的瘋搶令牌情況,因為令牌桶裡有足夠的令牌,使得來的一大波請求都能夠拿到令牌。但這種情況一般只是短時間的,不會太長久,隨後它會趨於一定速率的處理請求。
瞭解了令牌桶控制速率的機制,我們就不難理解下面的limit模組的選項了
--limit # [/second|/minute/hour|/day] ,次選項用於指定其生成令牌的速率
--limit-burst number ,此選項用於指定令牌桶裡能夠存放的令牌數量,也就是桶的大小
示例:允許所有主機ping 192.168.0.99 ,令牌桶裡的令牌最大容量為5個,生成令牌的速率是每分鐘生成10,來控制客戶端ping服務端
[root@test ~]# iptables -F [root@test ~]# iptables -nvL Chain INPUT (policy ACCEPT 6 packets, 396 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 4 packets, 384 bytes) pkts bytes target prot opt in out source destination [root@test ~]# iptables -A INPUT -d 192.168.0.99 -p icmp --icmp-type 8 -m limit --limit 10/minute --limit-burst 5 -j ACCEPT [root@test ~]# iptables -A INPUT -d 192.168.0.99 -p icmp -j DROP [root@test ~]# iptables -nvL Chain INPUT (policy ACCEPT 19 packets, 1332 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT icmp -- * * 0.0.0.0/0 192.168.0.99 icmptype 8 limit: avg 10/min burst 5 0 0 DROP icmp -- * * 0.0.0.0/0 192.168.0.99 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 13 packets, 1212 bytes) pkts bytes target prot opt in out source destination [root@test ~]#
提示:本人之所以要加一條拒絕所有icmp的請求規則,是因為我的INPUT鏈預設策略是ACCEPT,如果預設規則是REJECT或者DROP 是可以不用加第二條規則
測試:用客戶端ping 192.168.0.99看看其回覆報文有什麼特點,是不是起到了控制速率的效果
提示:我們從上面測試結果可以看到,ping請求的迴應包序號,最開始它是順序的,過了5個包後,基本上就是6秒一個迴應包,這裡的原因就像我們上面說的,最開始令牌桶裡有5個令牌,一開始請求的時候,請求報文能夠拿到令牌,過一段時間後,令牌桶裡的令牌不足了,所以在令牌生成的這一段時間裡的請求報文,防火牆是匹配到第二條規則裡,所以給拒絕掉了,當令牌桶裡有新的令牌時,去請求的報文就可以拿到一個令牌,從而得到響應報文,所以我們看到的響應報文,也是基於令牌生成的速率來的。這就是為什麼我們看到的迴應報文序列號 是每隔6秒有一個迴應包的原因。
2、state擴充套件
state模組是根據連線追蹤機制去檢查連線的狀態,使用這個模組去匹配報文時比較消耗防火牆資源的,因為防火牆要在其記憶體維護一張連線追蹤表,這個表記錄著請求本機和響應之間的關係。每檢查一次請求報文,它都會去這個表裡看一看,是不是之前來過的,基於某一狀態來追蹤報文的合法性。
state狀態有如下幾種:
NEW:這種狀態表示新發出的請求報文;連線追蹤資訊表中不存在此連結的相關資訊條目,因此會識別成第一次發出的請求;
ESTABLISHED:此狀態表示,NEW狀態之後,連線追蹤資訊表中為其建立的條目失效之前期間內所進行的通訊狀態
RELATED:此狀態表示新發起的請求,但與已連線相關聯的連線,比如FTP協議的資料連線與命令連線之間的關係
INVALID:此狀態表示無效的連線,如flag標記不正確的連線
UNTRACKED:此狀態表示未進行追蹤的連線,如raw表中關閉追蹤的連線
[!] --state state,此選項表示指定其連線追蹤狀態,這個選項指定的值就是上面幾種狀態的一種或多種。
示例:在INPUT鏈上新增對其指定埠的指定狀態連線給予放行
[root@test ~]# iptables -F [root@test ~]# iptables -nvL Chain INPUT (policy ACCEPT 9 packets, 620 bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 6 packets, 712 bytes) pkts bytes target prot opt in out source destination [root@test ~]# iptables -A INPUT -p tcp -m multiport --dports 23,41319 -m state --state NEW,ESTABLISHED -j ACCEPT [root@test ~]# iptables -A INPUT -j DROP [root@test ~]# iptables -A OUTPUT -p tcp -m multiport --sports 23,41319 -m state --state ESTABLISHED -j ACCEPT [root@test ~]# iptables -A OUTPUT -j DROP [root@test ~]# iptables -nvL Chain INPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 364 27040 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 multiport dports 23,41319 state NEW,ESTABLISHED 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 59 5460 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 multiport sports 23,41319 state ESTABLISHED 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0 [root@test ~]#
提示:以上規則表示放行INPUT鏈上連線狀態為NEW,ESTABLISHED的連線,在OUTPUT鏈上允許放行狀態為ESTABLISHED的連線
測試:用客戶端去連線伺服器
提示:可以看到我們用客戶端去連線服務端是沒有問題的。
提示:在服務端檢視防火牆規則,也看到了對應的規則上匹配到了響應的資料報文
在服務端我們可以檢視/proc/net/conntrack檔案,這個檔案中就是我們說到的連線追蹤資訊表
[root@test ~]# cat /proc/net/nf_conntrack ipv4 2 tcp 6 299 ESTABLISHED src=192.168.0.232 dst=192.168.0.99 sport=8004 dport=41319 src=192.168.0.99 dst=192.168.0.232 sport=41319 dport=8004 [ASSURED] mark=0 zone=0 use=2 ipv4 2 tcp 6 431993 ESTABLISHED src=192.168.0.151 dst=192.168.0.99 sport=39715 dport=23 src=192.168.0.99 dst=192.168.0.151 sport=23 dport=39715 [ASSURED] mark=0 zone=0 use=2 ipv4 2 tcp 6 235 ESTABLISHED src=192.168.0.99 dst=192.168.0.99 sport=36426 dport=3306 src=192.168.0.99 dst=192.168.0.99 sport=3306 dport=36426 [ASSURED] mark=0 zone=0 use=2 [root@test ~]#
提示:可以看到我們指定放行的狀態連線的主機資訊都在裡面。我們前面說過這個連線追蹤資訊表它是有大小和時效的,我們怎麼看本機的連線追蹤最大值和失效呢,在/proc/sys/net/nf_conntrack_max 檔案中就記錄了最大連線追蹤的條目個數,在/proc/sys/net/netfilter/這個目錄裡就定義了各種協議的連線追蹤時長,接下來我們來看看這些檔案
[root@test ~]# cat /proc/sys/net/nf_conntrack_max 65536 [root@test ~]# ls /proc/sys/net/netfilter/ nf_conntrack_acct nf_conntrack_helper nf_conntrack_tcp_timeout_close nf_conntrack_buckets nf_conntrack_icmp_timeout nf_conntrack_tcp_timeout_close_wait nf_conntrack_checksum nf_conntrack_log_invalid nf_conntrack_tcp_timeout_established nf_conntrack_count nf_conntrack_max nf_conntrack_tcp_timeout_fin_wait nf_conntrack_dccp_loose nf_conntrack_sctp_timeout_closed nf_conntrack_tcp_timeout_last_ack nf_conntrack_dccp_timeout_closereq nf_conntrack_sctp_timeout_cookie_echoed nf_conntrack_tcp_timeout_max_retrans nf_conntrack_dccp_timeout_closing nf_conntrack_sctp_timeout_cookie_wait nf_conntrack_tcp_timeout_syn_recv nf_conntrack_dccp_timeout_open nf_conntrack_sctp_timeout_established nf_conntrack_tcp_timeout_syn_sent nf_conntrack_dccp_timeout_partopen nf_conntrack_sctp_timeout_heartbeat_acked nf_conntrack_tcp_timeout_time_wait nf_conntrack_dccp_timeout_request nf_conntrack_sctp_timeout_heartbeat_sent nf_conntrack_tcp_timeout_unacknowledged nf_conntrack_dccp_timeout_respond nf_conntrack_sctp_timeout_shutdown_ack_sent nf_conntrack_timestamp nf_conntrack_dccp_timeout_timewait nf_conntrack_sctp_timeout_shutdown_recd nf_conntrack_udp_timeout nf_conntrack_events nf_conntrack_sctp_timeout_shutdown_sent nf_conntrack_udp_timeout_stream nf_conntrack_events_retry_timeout nf_conntrack_tcp_be_liberal nf_log nf_conntrack_expect_max nf_conntrack_tcp_loose nf_log_all_netns nf_conntrack_generic_timeout nf_conntrack_tcp_max_retrans [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_icmp_timeout 30 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_udp_timeout 30 [root@test ~]#
提示:可以看到/proc/sys/net/netfilter/這個目錄下的檔案都記錄了對應協議的超時時間。而/proc/sys/net/nf_conntrack_max這個檔案中記錄了連線追蹤表裡最大記錄連線追蹤資訊的條目個數。我們可以通過修改對應的檔案來調節連線追蹤表的大小和個協議失效時長。
iptables的連線追蹤表最大容量由/proc/sys/net/nf_conntrack_max檔案中定義,各種狀態的連線超時後會從連線追蹤表中刪除;當連線追蹤表滿了,後續的連線可能會超時,這個時候我們有兩種解決辦法:第一個就是加大連線追蹤表容量,前提是我們要有足夠的記憶體去存這個連線追蹤表;其次我們還可以把各個狀態的超時降低,讓其連線追蹤表裡的條目能夠很快的騰出空間來記錄新的狀態的連線追蹤資訊
1、加大nf_conntrack_max值
編輯/etc/sysctl.conf 把如下內容新增到該檔案中,然後儲存
net.nf_conntrack_max = 393216
net.netfilter.nf_conntrack_max = 393216
當然後面的值可以根據情況自己定義一個合適大小的值
[root@test ~]# cat /etc/sysctl.conf # sysctl settings are defined through files in # /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/. # # Vendors settings live in /usr/lib/sysctl.d/. # To override a whole file, create a new file with the same in # /etc/sysctl.d/ and put new settings there. To override # only specific settings, add a file with a lexically later # name in /etc/sysctl.d/ and put new settings there. # # For more information, see sysctl.conf(5) and sysctl.d(5). net.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_max = 393216 [root@test ~]# sysctl -p net.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_max = 393216 [root@test ~]# cat /proc/sys/net/nf_conntrack_max 393216 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_max 393216 [root@test ~]#
提示:當然把對應的值寫到檔案中是永久更改的方式,也就是下一次重新開機,這個值不會變。如果想臨時測試下,我們可以用echo 命令 echo 一個值到/proc/sys/net/nf_conntrack_max檔案中即可
2、降低 nf_conntrack timeout時間
編輯/etc/sysctl.conf 把以下內容寫入其中,然後儲存
net.netfilter.nf_conntrack_tcp_timeout_established = 300
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 1
[root@test ~]# cat /etc/sysctl.conf # sysctl settings are defined through files in # /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/. # # Vendors settings live in /usr/lib/sysctl.d/. # To override a whole file, create a new file with the same in # /etc/sysctl.d/ and put new settings there. To override # only specific settings, add a file with a lexically later # name in /etc/sysctl.d/ and put new settings there. # # For more information, see sysctl.conf(5) and sysctl.d(5). net.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_tcp_timeout_established = 300 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 1 [root@test ~]# sysctl -p net.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_max = 393216 net.netfilter.nf_conntrack_tcp_timeout_established = 300 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120 net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 1 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established 300 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait 120 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait 60 [root@test ~]# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait 1 [root@test ~]#
提示:我們把對應的引數和值寫到/etc/sysctl.conf檔案中,然後用sysctl -p 去重讀配置檔案,讓其對應的檔案中的值發生變化。這種方式是修改核心引數常規的方式。同樣我們只是想測試下,不想永久的修改,可以選擇用echo命令往對應檔案中寫入對應的值
開放被動模式的ftp服務
眾所周知ftp被動模式下,其資料埠是隨機的,也就是說我們在防火牆上配置是相當麻煩的,可以說沒法用匹配埠的方式去配置防火牆,我們需要用到連線追蹤功能,我們知道FTP 的資料埠是通過命令埠21去協商出來的一個埠,客戶端和服務端協商好一個隨機埠,然後開始傳輸資料,在防火牆上我們需要配置只要和21號埠有關聯的我們都給開放,這樣一來我們防火牆匹配報文就可以匹配到和21號埠相關的資料埠,從而實現放行FTP資料埠的目的。預設情況下Linux系統預設裝載的連線追蹤模組對於FTP是不生效的,針對FTP連線追蹤我們需要重新載入專用的連線追蹤模組nf_conntrack_ftp 接下來我們來看看系統是否有這個模組。
[root@test ~]# ls /lib/modules/3.10.0-693.el7.x86_64/kernel/net/netfilter/|grep -E *.ftp nf_conntrack_ftp.ko.xz nf_conntrack_tftp.ko.xz nf_nat_ftp.ko.xz nf_nat_tftp.ko.xz [root@test ~]#
提示:可以看到我們核心模組目錄裡有nf_conntrack_ftp這個模組。有這個模組但不一定裝載了,接下來還要檢查系統是否轉載了
[root@test ~]# lsmod |grep -E *.ftp [root@test ~]#
提示:可以看到系統沒有裝載任何和FTP有關的模組
[root@test ~]# modprobe nf_conntrack_ftp [root@test ~]# lsmod |grep -E *.ftp nf_conntrack_ftp 18638 0 nf_conntrack 137239 9 ip_vs,nf_nat,xt_connlimit,nf_nat_ipv4,xt_conntrack,nf_nat_masquerade_ipv4,nf_conntrack_netlink,nf_conntrack_ftp,nf_conntrack_ipv4 [root@test ~]#
提示:modprobe命令是用來裝載指定模組的,這種方式是臨時裝載,如果我們重啟系統後,這個模組它不會重新去裝載,要想開機自動裝載對應的模組,我們可以選擇把要裝載的模組名稱寫到/etc/sysconfig/iptables-config配置檔案中,如下所示
[root@test ~]# head /etc/sysconfig/iptables-config # Load additional iptables modules (nat helpers) # Default: -none- # Space separated list of nat helpers (e.g. 'ip_nat_ftp ip_nat_irc'), which # are loaded after the firewall rules are applied. Options for the helpers are # stored in /etc/modprobe.conf. IPTABLES_MODULES="nf_conntrack_ftp" # Unload modules on restart and stop # Value: yes|no, default: yes # This option has to be 'yes' to get to a sane state for a firewall [root@test ~]#
提示:如果有多個模組需要載入,可以用空格把多個模組名稱隔開
載入了專用的模組後,我們就可以寫防火牆規則,來放行被動模式下的FTP
測試:在寫規則前,我們先測試下,FTP是否能夠通過客戶端訪問
提示:防火牆INPUT和OUTPUT鏈上預設規則是DROP,然後對應的規則上沒有開放其21號埠,所以我們用客戶端連線21號埠是沒法連線的,接下來我們在防火牆上配置規則,放行其21號埠的報文
[root@test ~]# iptables -P INPUT ACCEPT [root@test ~]# iptables -P OUTPUT ACCEPT [root@test ~]# iptables -F [root@test ~]# iptables -A INPUT -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT [root@test ~]# iptables -A OUTPUT -p tcp -m state --state ESTABLISHED -j ACCEPT [root@test ~]# iptables -A INPUT -p tcp -m multiport --dports 21,41319 -m state --state NEW -j ACCEPT [root@test ~]# iptables -P INPUT DROP [root@test ~]# iptables -P OUTPUT DROP [root@test ~]# iptables -nvL Chain INPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 412 29132 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 multiport dports 21,41319 state NEW Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 165 15340 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state ESTABLISHED [root@test ~]#
提示:我們把INPUT和OUTPUT鏈上的預設規則配置成ACCEPT,然後在清楚之前配置的規則,然後在INPUT鏈上允許放行狀態為ESTABLISHED和RELATED的報文,在OUTPUT鏈上允許放行狀態為ESTABLISHED的資料報文,然後在INPUT鏈上放行21號埠和SSH連線埠的狀態為NEW的資料報文,最後我們把INPUT和OUTPUT鏈上的預設策略更改為DROP,這樣配置後,在OUTPUT鏈上,只要報文狀態是ESTABLISHED的都給予放行處理,在INPUT鏈上,如果是請求的目標埠是21號且狀態為NEW的都給予放行,這樣一來首先客戶端登入FTP是沒有問題的,其次是資料鏈鋸,在INPUT鏈上我們配置了狀態為RELATED的資料報文是允許放行,這樣一來FTP的資料鏈路應該是沒有問題。接下來我們在客戶端連線FTP伺服器,看看其資料鏈路的報文是否都被允許了
測試:在客戶端用FTP工具連線FTP伺服器,看看其資料鏈路是否超時
提示:可以看到在客戶端連線FTP伺服器是可以正常的登入和下載檔案,充分說明了我們配置的防火牆規則是沒有問題的
提示:在服務端我們也可以看到INPUT鏈上的第二條規則就匹配到4個包,而其他規則匹配了大量的包,為什麼第二條規則匹配的報文這麼少呢?這時因為第二條規則只有新客戶端最開始去連線FTP伺服器時 它才能匹配得到,後續的報文狀態要麼是ESTABLISHED的狀態,要麼是RELATED狀態的報文。所以在INPUT和OUTPUT鏈上的第一條規則相當於一個萬能的規則,只要其狀態符合通行的條件報文就可以通過。有了state這個擴充套件模組,我們發現我們寫的規則可以大大的減少很多,很多規則可以用一條就可以代替。這裡還需要注意一點的是,用state擴充套件匹配條件,對伺服器的效能有影響,我們在使用state模組的功能的同時,還需要考慮它伺服器的效能