[轉]Iptables之nf_conntrack模塊


nf_conntrack模塊
nf_conntrack(在老版本的 Linux 內核中叫 ip_conntrack)是一個內核模塊,用於跟蹤一個連接的狀態的。連接狀態跟蹤可以供其他模塊使用,最常見的兩個使用場景是 iptables 的 nat 的 state 模塊。 iptables 的 nat 通過規則來修改目的/源地址,但光修改地址不行,我們還需要能讓回來的包能路由到最初的來源主機。這就需要借助 nf_conntrack 來找到原來那個連接的記錄才行。而 state 模塊則是直接使用 nf_conntrack 里記錄的連接的狀態來匹配用戶定義的相關規則。例如下面這條 INPUT 規則用於放行 80 端口上的狀態為 NEW 的連接上的包。

iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT。

iptables中的狀態檢測功能是由state選項來實現iptable的。對這個選項,在iptables的手冊頁中有以下描述:

state

這個模塊能夠跟蹤分組的連接狀態(即狀態檢測)。

格式:--state XXXXX

這里,state是一個用逗號分割的列表,表示要匹配的連接狀態。

在iptables中有四種狀態:NEW,ESTABLISHED,RELATED,INVALID。

NEW,表示這個分組需要發起一個連接,或者說,分組對應的連接在兩個方向上都沒有進行過分組傳輸。NEW說明 這個包是我們看到的第一個包。意思就是,這是conntrack模塊看到的某個連接第一個包,它即將被匹配了。比如,我們看到一個SYN包,是我們所留意 的連接的第一個包,就要匹配它。第一個包也可能不是SYN包,但它仍會被認為是NEW狀態。比如一個特意發出的探測包,可能只有RST位,但仍然是 NEW。

ESTABLISHED,表示分組對應的連接已經進行了雙向的分組傳輸,也就是說連接已經建立,而且會繼續匹配 這個連接的包。處於ESTABLISHED狀態的連接是非常容易理解的。只要發送並接到應答,連接就是ESTABLISHED的了。一個連接要從NEW變 為ESTABLISHED,只需要接到應答包即可,不管這個包是發往防火牆的,還是要由防火牆轉發的。ICMP的錯誤和重定向等信息包也被看作是 ESTABLISHED,只要它們是我們所發出的信息的應答。

RELATED,表示分組要發起一個新的連接,但是這個連接和一個現有的連接有關,例如:FTP的數據傳輸連接 和控制連接之間就是RELATED關系。RELATED是個比較麻煩的狀態。當一個連接和某個已處於ESTABLISHED狀態的連接有關系時,就被認為 是RELATED的了。換句話說,一個連接要想是RELATED的,首先要有一個ESTABLISHED的連接。這個ESTABLISHED連接再產生一 個主連接之外的連接,這個新的連接就是RELATED的了,當然前提是conntrack模塊要能理解RELATED。ftp是個很好的例子,FTP- data連接就是和FTP-control有RELATED的。還有其他的例子,

INVAILD,表示分組對應的連接是未知的,說明數據包不能被識別屬於哪個連接或沒有任何狀態。有幾個原因可以產生這種情況,比如,內存溢出,收到不知屬於哪個連接的ICMP錯誤信息。一般地,我們DROP這個狀態的任何東西。

nf_conntrack模塊常用命令
查看nf_conntrack表當前連接數
cat /proc/sys/net/netfilter/nf_conntrack_count

查看nf_conntrack表最大連接數
cat /proc/sys/net/netfilter/nf_conntrack_max

通過dmesg可以查看nf_conntrack的狀況:
dmesg |grep nf_conntrack

查看存儲conntrack條目的哈希表大小,此為只讀文件
cat /proc/sys/net/netfilter/nf_conntrack_buckets

查看nf_conntrack的TCP連接記錄時間
cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established

通過內核參數查看命令,查看所有參數配置
sysctl -a | grep nf_conntrack

通過conntrack命令行工具查看conntrack的內容
yum install -y conntrack
conntrack -L

加載對應跟蹤模塊
[root@plop ~]# modprobe /proc/net/nf_conntrack_ipv4
[root@plop ~]# lsmod | grep nf_conntrack
nf_conntrack_ipv4 9506 0
nf_defrag_ipv4 1483 1 nf_conntrack_ipv4
nf_conntrack_ipv6 8748 2
nf_defrag_ipv6 11182 1 nf_conntrack_ipv6
nf_conntrack 79758 3 nf_conntrack_ipv4,nf_conntrack_ipv6,xt_state
ipv6 317340 28 sctp,ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6

移除 nf_conntrack 模塊
$ sudo modprobe -r xt_NOTRACK nf_conntrack_netbios_ns nf_conntrack_ipv4 xt_state
$ sudo modprobe -r nf_conntrack

查看當前的連接數:
grep nf_conntrack /proc/slabinfo

查出目前 nf_conntrack 的排名:
cat /proc/net/nf_conntrack | cut -d ' ' -f 10 | cut -d '=' -f 2 | sort | uniq -c | sort -nr | head -n 10

nf_conntrack會話表的內容解釋
會話表樣例
通過conntrack -L與/proc/net/nf_conntrack是完全一樣的,除了少了前面的兩列。
下面以cat /proc/net/nf_conntrack為例進行說明:

ipv4 2 tcp 6 25 SYN_SENT src=182.168.77.7 dst=42.236.9.57 sport=57430 dport=443 [UNREPLIED] src=42.236.9.57 dst=182.168.77.7 sport=443 dport=57430 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
ipv4 2 tcp 6 299 ESTABLISHED src=172.18.15.56 dst=172.18.15.96 sport=40248 dport=22 src=172.18.15.96 dst=172.18.15.56 sport=22 dport=40248 [ASSURED] mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
ipv4 2 tcp 6 5 SYN_SENT src=182.168.77.7 dst=221.181.72.250 sport=57428 dport=443 [UNREPLIED] src=221.181.72.250 dst=182.168.77.7 sport=443 dport=57428 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
ipv4 2 tcp 6 1 SYN_SENT src=182.168.77.7 dst=221.181.72.250 sport=57427 dport=80 [UNREPLIED] src=221.181.72.250 dst=182.168.77.7 sport=80 dport=57427 mark=0 secctx=system_u:object_r:unlabeled_t:s0 zone=0 use=2
每一列表達的意思
第一列:網絡層協議名字。
第二列:網絡層協議號。
第三列:傳輸層協議名字。
第四列:傳輸層協議號。
第五列:無后續包進入時無效的秒數,即老化時間。
第六列:不是所有協議都有,連接狀態。
其它的列都是通過名字的方式(key與value對)表述,或和呈現標識([UNREPLIED], [ASSURED], …)。一行的不同列可能包含相同的名字(例如src和dst),第一個表示請求方,第二個表示應答方。
呈現標識含義
[ASSURED]: 在兩個方面(即請求和響應)方向都看到了流量。
[UNREPLIED]: 尚未在響應方向上看到流量。如果連接跟蹤緩存溢出,則首先刪除這些連接。
請注意,某些列名僅出現在特定協議中(例如,TCP和UDP的sport和dport,ICMP的type和code)。 僅當內核使用特定選項構建時,才會顯示其他列名稱(例如mark)。

舉例說明
ipv4 2 tcp 6 300 ESTABLISHED src=1.1.1.2 dst=2.2.2.2 sport=2000 dport=80 src=2.2.2.2 dst=1.1.1.1 sport=80 dport=12000 [ASSURED] mark=0 use=2
屬於從主機1.1.1.2,端口2000到主機2.2.2.2,端口80的已建立的TCP連接,從中將響應發送到主機1.1.1.2,端口2000,在五分鍾內超時。對於此連接,已在兩個方向上看到數據包。

ipv4 2 icmp 1 3 src=1.1.1.2 dst=1.1.1.1 type=8 code=0 id=32354 src=1.1.1.1 dst=1.1.1.2 type=0 code=0 id=32354 mark=0 use=2
屬於從主機1.1.1.2到主機1.1.1.1的ICMP回應請求數據包,具有從主機1.1.1.1到主機1.1.1.2的預期回應應答數據包,在三秒內超時。響應目標主機不一定與請求源主機相同,因為請求源地址可能已被響應目標主機偽裝。

主要標識
請注意,以下信息可能不是最新信息!

Fields available for all entries:

bytes (if accounting is enabled, request and response)
delta-time (if CONFIG_NF_CONNTRACK_TIMESTAMP is enabled)
dst (request and response)
mark (if CONFIG_NF_CONNTRACK_MARK is enabled)
packets (if accounting is enabled, request and response)
secctx (if CONFIG_NF_CONNTRACK_SECMARK is enabled)
src (request and response)
use
zone (if CONFIG_NF_CONNTRACK_ZONES is enabled)
Fields available for dccp, sctp, tcp, udp and udplite transmission layer protocols:

dport (request and response)
sport (request and response)
Fields available for icmp transmission layer protocol:

code (request and response)
id (request and response)
type (request and response)
Fields available for gre transmission layer protocol:

dstkey (request and response)
srckey (request and response)
stream_timeout
timeout
Allowed values for the sixth field:

dccp transmission layer protocol
CLOSEREQ
CLOSING
IGNORE
INVALID
NONE
OPEN
PARTOPEN
REQUEST
RESPOND
TIME_WAIT

sctp transmission layer protocol
CLOSED
COOKIE_ECHOED
COOKIE_WAIT
ESTABLISHED
NONE
SHUTDOWN_ACK_SENT
SHUTDOWN_RECD
SHUTDOWN_SENT

tcp transmission layer protocol
CLOSE
CLOSE_WAIT
ESTABLISHED
FIN_WAIT
LAST_ACK
NONE
SYN_RECV
SYN_SENT
SYN_SENT2
TIME_WAIT

nf_conntrack相關內核參數和解釋
參考內核幫助文檔/usr/share/doc/kernel-doc-3.10.0/Documentation/networking/nf_conntrack-sysctl.txt
/proc/sys/net/netfilter/nf_conntrack_*:

nf_conntrack_acct
值類型:BOOLEAN
0 - disabled (default)
not 0 - enabled
啟用連接跟蹤流記帳。64位字節和數據包每個流量的計數器被添加。

nf_conntrack_buckets
值類型:INTEGER (read-only)
哈希表的大小。 如果在模塊加載期間未指定為參數,則通過將總內存除以16384來計算默認大小以確定存儲區的數量,但是哈希表將永遠不會少於32並且限制為16384個存儲區。 對於內存超過4GB的系統,它將是65536個桶。

nf_conntrack_checksum
值類型:BOOLEAN
0 - disabled
not 0 - enabled (default)
驗證傳入數據包的校驗和。 具有錯誤校驗和的數據包處於INVALID狀態。 如果啟用此選項,則不會考慮此類數據包進行連接跟蹤。

nf_conntrack_count
值類型:INTEGER (read-only)
當前分配的流條目數。

nf_conntrack_events
值類型:BOOLEAN
0 - disabled
not 0 - enabled (default)
如果啟用此選項,則連接跟蹤代碼將通過ctnetlink為用戶空間提供連接跟蹤事件。

nf_conntrack_events_retry_timeout
值類型:INTEGER (seconds)
default 15
此選項僅在使用“可靠連接跟蹤事件”時才相關。 通常,ctnetlink是“有損”的,也就是說,當用戶空間監聽器無法跟上時,事件通常會被丟棄。
用戶空間可以請求“可靠的事件模式”。 當此模式處於活動狀態時,conntrack將僅在事件發布后銷毀。 如果事件傳遞失敗,則內核會定期重新嘗試將事件發送到用戶空間。
這是內核在重新嘗試傳遞destroy事件時應使用的最大間隔。
數字越大意味着交付重試次數越少,處理待辦事項的時間就越長。

nf_conntrack_expect_max
值類型:INTEGER
期望表的最大大小。 默認值為nf_conntrack_buckets / 256.最小值為1。

nf_conntrack_frag6_high_thresh
值類型:INTEGER
用於重組IPv6片段的最大內存。 當為達到重組目標時分配nf_conntrack_frag6_high_thresh字節的內存時,若超出此值片段處理程序將拋出數據包。

nf_conntrack_frag6_timeout
值類型:INTEGER (seconds)
default 60
ipv6分片在內存中保存的老化時間。

nf_conntrack_generic_timeout
值類型:INTEGER (seconds)
default 600
通用超時的默認值。 這指的是第4層未知/不支持的協議。

nf_conntrack_helper
值類型:BOOLEAN
0 - disabled
not 0 - enabled (default)
啟用自動conntrack幫助程序分配。

nf_conntrack_icmp_timeout
值類型:INTEGER (seconds)
default 30
ICMP連接狀態超時的默認值。

nf_conntrack_icmpv6_timeout
值類型:INTEGER (seconds)
default 30
ICMP6連接狀態超時的默認值。

nf_conntrack_log_invalid
值類型:INTEGER
0 - disable (default)
1 - log ICMP packets
6 - log TCP packets
17 - log UDP packets
33 - log DCCP packets
41 - log ICMPv6 packets
136 - log UDPLITE packets
255 - log packets of any protocol
根據值類型記錄指定類型無效數據包。

nf_conntrack_max
值類型:INTEGER
連接跟蹤表的大小。 默認值為nf_conntrack_buckets值* 4。

nf_conntrack_tcp_be_liberal
值類型:BOOLEAN
0 - disabled (default)
not 0 - enabled
Be conservative in what you do, be liberal in what you accept from others.If it’s non-zero, we mark only out of window RST segments as INVALID.

nf_conntrack_tcp_loose
值類型:BOOLEAN
0 - disabled
not 0 - enabled (default)
如果它設置為零,我們將禁用拾取已建立的連接。
它的意思是,是否僅僅允許為經過TCP三次握手的流創建nf_conntrack表項還是說為任意收到的TCP數據包(有可能是一個構造出來的攻擊包)查詢未果后均創建新的nf_conntrack表項。

nf_conntrack_tcp_max_retrans
值類型:INTEGER
default 3
在未收到來自目標的(可接受)ACK的情況下可以重新傳輸的最大數據包數。 如果達到此數字,將啟動更短的計時器。

nf_conntrack_tcp_timeout_close
值類型:INTEGER (seconds)
default 10

nf_conntrack_tcp_timeout_close_wait
值類型:INTEGER (seconds)
default 60

nf_conntrack_tcp_timeout_established
值類型:INTEGER (seconds)
default 432000 (5 days)
默認是432000=3600245即5天的超時時間,超時后清空對應的那條記錄。

nf_conntrack_tcp_timeout_fin_wait
值類型:INTEGER (seconds)
default 120

nf_conntrack_tcp_timeout_last_ack
值類型:INTEGER (seconds)
default 30

nf_conntrack_tcp_timeout_max_retrans
值類型:INTEGER (seconds)
default 300

nf_conntrack_tcp_timeout_syn_recv
值類型:INTEGER (seconds)
default 60

nf_conntrack_tcp_timeout_syn_sent
值類型:INTEGER (seconds)
default 120

nf_conntrack_tcp_timeout_time_wait
值類型:INTEGER (seconds)
default 120

nf_conntrack_tcp_timeout_unacknowledged
值類型:INTEGER (seconds)
default 300

nf_conntrack_timestamp
值類型:BOOLEAN
0 - disabled (default)
not 0 - enabled
啟用連接跟蹤流時間戳。

nf_conntrack_udp_timeout
值類型:INTEGER (seconds)
default 30

nf_conntrack_udp_timeout_stream2
值類型:INTEGER (seconds)
default 180
如果檢測到UDP流,將使用此擴展超時。

還有多少秒這條會話信息會從跟蹤表清除,取決於超時參數的配置,以及是否有包傳輸,有包傳輸時,這個時間會重置為超時時間。

如何判斷會話表是否滿
當會話表中的記錄大於內核設置nf_conntrack_max的值時,會導致會話表滿。

nf_conntrack_max - INTEGER
Size of connection tracking table. Default value is
nf_conntrack_buckets value * 4.
錯誤例子: less /var/log/messages

Nov 3 23:30:27 digoal_host kernel: : [63500383.870591] nf_conntrack: table full, dropping packet.
Nov 3 23:30:27 digoal_host kernel: : [63500383.962423] nf_conntrack: table full, dropping packet.
Nov 3 23:30:27 digoal_host kernel: : [63500384.060399] nf_conntrack: table full, dropping packet.

會話表滿的解決辦法
nf_conntrack table full的問題,會導致丟包,影響網絡質量,嚴重時甚至導致網絡不可用。

解決方法舉例:
1、排查是否DDoS攻擊,如果是,從預防攻擊層面解決問題。

2、清空會話表。

重啟iptables,會自動清空nf_conntrack table。注意,重啟前先保存當前iptables配置(iptables-save > /etc/sysconfig/iptables ; service iptables restart)。

3、應用程序正常關閉會話

設計應用時,正常關閉會話很重要。

4、加大表的上限(需要考慮內存的消耗)

例舉故障原因
內核參數 net.nf_conntrack_max 系統默認值為”65536”,當nf_conntrack模塊被裝置且服務器上連接超過這個設定的值時,系統會主動丟掉新連接包,直到連接小於此設置值才會恢復。同時內核參數“net.netfilter.nf_conntrack_tcp_timeout_established”系統默認值為”432000”,代表nf_conntrack的TCP連接記錄時間默認是5天,致使nf_conntrack的值減不下來,丟包持續時間長。

nf_conntrack模塊在首次裝載或重新裝載時,內核參數net.nf_conntrack_max會重新設置為默認值“65536”,並且不會調用sysctl設置為我們的預設值。

觸發nf_conntrack模塊首次裝載比較隱蔽,任何調用IPtable NAT功能的操作都會觸發。當系統沒有掛載nf_conntrack模塊時,iptables 相關命令(iptables -L -t nat)就成觸發nf_conntrack模塊裝置,致使net.nf_conntrack_max 重設為65536。

觸發nf_conntrack模塊重新裝載的操作很多,CentOS6 中“service iptables restart”,CentOS7中“systemctl restart iptables.service”都會觸發設置重置,致使net.nf_conntrack_max 重設為65536。

重要的幾個配置文件
nf_conntrack_max決定連接跟蹤表的大小,當nf_conntrack模塊被裝置且服務器上連接超過這個設定的值時,系統會主動丟掉新連接包,直到連接小於此設置值才會恢復。
nf_conntrack_buckets決定存儲conntrack條目的哈希表大小,若是單方面修改nf_conntrack_max,而不修改nf_conntrack_buckets,只是影響查找速度,掛在不了桶上的新跟蹤項目,會掛在到桶中的鏈表上(原理為hash表結構)。
nf_conntrack_tcp_timeout_established系統默認值為”432000”,代表nf_conntrack的TCP連接記錄時間默認是5天,致使nf_conntrack的值減不下來,丟包持續時間長。
通過修改這兩個值即可,但是nf_conntrack_buckets時個只讀文件,無法進行修改。

修改參數
或通過sysctl命令進行修改:
$ sysctl -w net.netfilter.nf_conntrack_max=1048576
$ sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600
$ sysctl -p #使生效
或是直接永久性修改永久生效
vi /etc/sysctl.conf
net.netfilter.nf_conntrack_max=1048576
net.netfilter.nf_conntrack_tcp_timeout_established=3600
對於上述解決方案無法修改nf_conntrack_buckets的參數,因為此為只讀文件,通過上述nf_conntrack-sysctl.txt文件可知知,可以通過模塊加載的時候設置參數。此時可以采用下面方案進行修改:
通過系統初始化腳本創建配置文件”/etc/modprobe.d/nf_conntrack.conf”, 內容為“options nf_conntrack hashsize=262144”,通過nf_conntrack模塊掛接參數”hashsize”自動設置“net.nf_conntrack_max=2097152”(nf_conntrack_max=hashsize*8),保證后續新初始化服務器配置正確。

通過自動化部署工具全網推送配置文件”/etc/modprobe.d/nf_conntrack.conf”, 內容為“options nf_conntrack hashsize=262144”,保證nf_conntrack模塊在首次裝載或重新裝載時“net.nf_conntrack_max”內核參數設置為我們預期的“2097152”。

更新系統初始化腳本,設置“net.netfilter.nf_conntrack_tcp_timeout_established=1800”,減少nf_conntrack的TCP連接記錄時間。

如果並不需要nf_conntrack及其相關模塊可以在/etc/modprobe.d目錄新建文件blacklist.conf ,文件中加入:install nf_conntrack /bin/false 這樣做的副作用是無法再使用Iptables NAT相關功能。

計算公式
可以增大 conntrack 的條目(sessions, connection tracking entries) CONNTRACK_MAX 或者增加存儲 conntrack 條目哈希表的大小 HASHSIZE
默認情況下,CONNTRACK_MAX 和 HASHSIZE 會根據系統內存大小計算出一個比較合理的值:
對於 CONNTRACK_MAX,其計算公式:
CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (ARCH / 32)
比如一個 64 位 48G 的機器可以同時處理 48*1024^3/16384/2 = 1572864 條 netfilter 連接。對於大於 1G 內存的系統,默認的 CONNTRACK_MAX 是 65535。

對於 HASHSIZE,默認的有這樣的轉換關系:
CONNTRACK_MAX = HASHSIZE * 8
這表示每個鏈接列表里面平均有 8 個 conntrack 條目。其真正的計算公式如下:
HASHSIZE = CONNTRACK_MAX / 8 = RAMSIZE (in bytes) / 131072 / (ARCH / 32)
比如一個 64 位 48G 的機器可以存儲 48*1024^3/131072/2 = 196608 的buckets(連接列表)。對於大於 1G 內存的系統,默認的 HASHSIZE 是 8192。

參考鏈接:
解決 nf_conntrack: table full, dropping packet 的幾種思路
Linux服務器丟包故障的解決思路及引申的TCP/IP協議棧理論
net.nf_conntrack_max 設置異常問題

(原文地址:https://clodfisher.github.io/2018/09/nf_conntrack/)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM