Iptables之nf_conntrack模塊


轉自https://clodfisher.github.io/2018/09/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、加大表的上限(需要考慮內存的消耗)

例舉故障原因

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

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

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

  4. 觸發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文件可知知,可以通過模塊加載的時候設置參數。此時可以采用下面方案進行修改:
    1. 通過系統初始化腳本創建配置文件”/etc/modprobe.d/nf_conntrack.conf”, 內容為“options nf_conntrack hashsize=262144”,通過nf_conntrack模塊掛接參數”hashsize”自動設置“net.nf_conntrack_max=2097152”(nf_conntrack_max=hashsize*8),保證后續新初始化服務器配置正確。

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

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

    4. 如果並不需要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 設置異常問題


免責聲明!

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



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